flac: Saner EOF handling
[cmus.git] / mad.c
blob0ae0199e7bf5af2b97c630aa7b5623fa52fafd35
1 /*
2 * Copyright 2004 Timo Hirvonen
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 as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
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
17 * 02111-1307, USA.
20 #include "ip.h"
21 #include "nomad.h"
22 #include "id3.h"
23 #include "ape.h"
24 #include "xmalloc.h"
25 #include "read_wrapper.h"
26 #include "debug.h"
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
35 /* ------------------------------------------------------------------------- */
37 static ssize_t read_func(void *datasource, void *buffer, size_t count)
39 struct input_plugin_data *ip_data = datasource;
41 return read_wrapper(ip_data, buffer, count);
44 static off_t lseek_func(void *datasource, off_t offset, int whence)
46 struct input_plugin_data *ip_data = datasource;
48 return lseek(ip_data->fd, offset, whence);
51 static int close_func(void *datasource)
53 struct input_plugin_data *ip_data = datasource;
55 return close(ip_data->fd);
58 static struct nomad_callbacks callbacks = {
59 .read = read_func,
60 .lseek = lseek_func,
61 .close = close_func
64 /* ------------------------------------------------------------------------- */
66 static int mad_open(struct input_plugin_data *ip_data)
68 struct nomad *nomad;
69 struct nomad_info info;
70 int rc, fast;
72 fast = 1;
73 rc = nomad_open_callbacks(&nomad, ip_data, fast, &callbacks);
74 switch (rc) {
75 case -NOMAD_ERROR_ERRNO:
76 return -1;
77 case -NOMAD_ERROR_FILE_FORMAT:
78 return -IP_ERROR_FILE_FORMAT;
80 ip_data->private = nomad;
82 nomad_info(nomad, &info);
84 /* always 16-bit signed little-endian */
85 ip_data->sf = sf_rate(info.sample_rate) | sf_channels(info.channels) |
86 sf_bits(16) | sf_signed(1);
87 return 0;
90 static int mad_close(struct input_plugin_data *ip_data)
92 struct nomad *nomad;
94 nomad = ip_data->private;
95 nomad_close(nomad);
96 ip_data->fd = -1;
97 ip_data->private = NULL;
98 return 0;
101 static int mad_read(struct input_plugin_data *ip_data, char *buffer, int count)
103 struct nomad *nomad;
105 nomad = ip_data->private;
106 return nomad_read(nomad, buffer, count);
109 static int mad_seek(struct input_plugin_data *ip_data, double offset)
111 struct nomad *nomad;
113 nomad = ip_data->private;
114 return nomad_time_seek(nomad, offset);
117 static int mad_read_comments(struct input_plugin_data *ip_data,
118 struct keyval **comments)
120 struct id3tag id3;
121 int fd, rc, save, i;
122 APETAG(ape);
123 GROWING_KEYVALS(c);
125 fd = open(ip_data->filename, O_RDONLY);
126 if (fd == -1) {
127 return -1;
129 d_print("filename: %s\n", ip_data->filename);
131 id3_init(&id3);
132 rc = id3_read_tags(&id3, fd, ID3_V1 | ID3_V2);
133 save = errno;
134 close(fd);
135 errno = save;
136 if (rc) {
137 if (rc == -1) {
138 d_print("error: %s\n", strerror(errno));
139 return -1;
141 d_print("corrupted tag?\n");
142 goto next;
145 for (i = 0; i < NUM_ID3_KEYS; i++) {
146 char *val = id3_get_comment(&id3, i);
148 if (val)
149 comments_add(&c, id3_key_names[i], val);
152 next:
153 id3_free(&id3);
155 rc = ape_read_tags(&ape, ip_data->fd, 0);
156 if (rc < 0)
157 goto out;
159 for (i = 0; i < rc; i++) {
160 char *k, *v;
161 k = ape_get_comment(&ape, &v);
162 if (!k)
163 break;
164 comments_add(&c, k, v);
165 free(k);
168 out:
169 ape_free(&ape);
171 keyvals_terminate(&c);
172 *comments = c.keyvals;
173 return 0;
176 static int mad_duration(struct input_plugin_data *ip_data)
178 struct nomad *nomad;
180 nomad = ip_data->private;
181 return nomad_time_total(nomad);
184 const struct input_plugin_ops ip_ops = {
185 .open = mad_open,
186 .close = mad_close,
187 .read = mad_read,
188 .seek = mad_seek,
189 .read_comments = mad_read_comments,
190 .duration = mad_duration
193 const char * const ip_extensions[] = { "mp3", "mp2", NULL };
194 const char * const ip_mime_types[] = {
195 "audio/mpeg", "audio/x-mp3", "audio/x-mpeg", NULL