summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer
authorharlekin <harlekin>2002-04-22 21:47:09 (UTC)
committer harlekin <harlekin>2002-04-22 21:47:09 (UTC)
commitf77f012023dbe7582a4b4297f61c6521ad8a3aa5 (patch) (unidiff)
tree3d41a0320169e8b2749e7cee98f14e0435fe05e3 /core/multimedia/opieplayer
parentcca7f8ae4f60ae9b6c704d200ab015233abdd4d7 (diff)
downloadopie-f77f012023dbe7582a4b4297f61c6521ad8a3aa5.zip
opie-f77f012023dbe7582a4b4297f61c6521ad8a3aa5.tar.gz
opie-f77f012023dbe7582a4b4297f61c6521ad8a3aa5.tar.bz2
get shoutcast support better, now all stream information are shown in the mediaplayer
Diffstat (limited to 'core/multimedia/opieplayer') (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/libmad/libmadplugin.cpp449
1 files changed, 228 insertions, 221 deletions
diff --git a/core/multimedia/opieplayer/libmad/libmadplugin.cpp b/core/multimedia/opieplayer/libmad/libmadplugin.cpp
index 7de4282..0f952f4 100644
--- a/core/multimedia/opieplayer/libmad/libmadplugin.cpp
+++ b/core/multimedia/opieplayer/libmad/libmadplugin.cpp
@@ -14,12 +14,14 @@
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20// largly modified by Maximilian Reiss <max.reiss@gmx.de>
21
20#include <stdio.h> 22#include <stdio.h>
21#include <stdarg.h> 23#include <stdarg.h>
22#include <stdlib.h> 24#include <stdlib.h>
23#include <sys/types.h> 25#include <sys/types.h>
24#include <sys/stat.h> 26#include <sys/stat.h>
25#include <fcntl.h> 27#include <fcntl.h>
@@ -28,13 +30,16 @@
28#include <ctype.h> 30#include <ctype.h>
29#include <errno.h> 31#include <errno.h>
30#include <time.h> 32#include <time.h>
31#include <locale.h> 33#include <locale.h>
32#include <math.h> 34#include <math.h>
33#include <assert.h> 35#include <assert.h>
36
34#include <qapplication.h> 37#include <qapplication.h>
38#include <qmessagebox.h>
39
35#include <qpe/config.h> 40#include <qpe/config.h>
36 41
37// for network handling 42// for network handling
38#include <netinet/in.h> 43#include <netinet/in.h>
39#include <netdb.h> 44#include <netdb.h>
40#include <sys/socket.h> 45#include <sys/socket.h>
@@ -195,51 +200,53 @@ int LibMadPlugin::udp_open(char *address, int port) {
195 struct hostent *host; 200 struct hostent *host;
196 int sock; 201 int sock;
197 202
198 stAddr.sin_family = AF_INET; 203 stAddr.sin_family = AF_INET;
199 stAddr.sin_port = htons(port); 204 stAddr.sin_port = htons(port);
200 205
201 if ((host = gethostbyname(address)) == NULL) 206 if ((host = gethostbyname(address)) == NULL) {
202 return (0); 207 return (0);
208 }
203 209
204 stAddr.sin_addr = *((struct in_addr *)host->h_addr_list[0]); 210 stAddr.sin_addr = *((struct in_addr *)host->h_addr_list[0]);
205 211
206 /* Create a UDP socket */ 212 /* Create a UDP socket */
207 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 213 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
208 return (0); 214 return (0);
215 }
209 216
210 /* Allow multiple instance of the client to share the same address and port */ 217 /* Allow multiple instance of the client to share the same address and port */
211 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&enable, sizeof(unsigned long int)) < 0) 218 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&enable, sizeof(unsigned long int)) < 0) {
212 return (0); 219 return (0);
220 }
213 221
214 /* If the address is multicast, register to the multicast group */ 222 /* If the address is multicast, register to the multicast group */
215 if (is_address_multicast(stAddr.sin_addr.s_addr)) 223 if (is_address_multicast(stAddr.sin_addr.s_addr)) {
216 {
217 /* Bind the socket to port */ 224 /* Bind the socket to port */
218 stLclAddr.sin_family = AF_INET; 225 stLclAddr.sin_family = AF_INET;
219 stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); 226 stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
220 stLclAddr.sin_port = stAddr.sin_port; 227 stLclAddr.sin_port = stAddr.sin_port;
221 if (bind(sock, (struct sockaddr *)&stLclAddr, sizeof(stLclAddr)) < 0) 228 if (bind(sock, (struct sockaddr *)&stLclAddr, sizeof(stLclAddr)) < 0) {
222 return (0); 229 return (0);
230 }
223 231
224 /* Register to a multicast address */ 232 /* Register to a multicast address */
225 stMreq.imr_multiaddr.s_addr = stAddr.sin_addr.s_addr; 233 stMreq.imr_multiaddr.s_addr = stAddr.sin_addr.s_addr;
226 stMreq.imr_interface.s_addr = INADDR_ANY; 234 stMreq.imr_interface.s_addr = INADDR_ANY;
227 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq)) < 0) 235 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq)) < 0) {
228 return (0); 236 return (0);
229 } 237 }
230 else 238 } else {
231 {
232 /* Bind the socket to port */ 239 /* Bind the socket to port */
233 stLclAddr.sin_family = AF_INET; 240 stLclAddr.sin_family = AF_INET;
234 stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); 241 stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
235 stLclAddr.sin_port = htons(0); 242 stLclAddr.sin_port = htons(0);
236 if (bind(sock, (struct sockaddr *)&stLclAddr, sizeof(stLclAddr)) < 0) 243 if (bind(sock, (struct sockaddr *)&stLclAddr, sizeof(stLclAddr)) < 0) {
237 return (0); 244 return (0);
245 }
238 } 246 }
239
240 return (sock); 247 return (sock);
241} 248}
242 249
243int LibMadPlugin::tcp_open(char *address, int port) { 250int LibMadPlugin::tcp_open(char *address, int port) {
244 struct sockaddr_in stAddr; 251 struct sockaddr_in stAddr;
245 struct hostent *host; 252 struct hostent *host;
@@ -247,27 +254,31 @@ int LibMadPlugin::tcp_open(char *address, int port) {
247 struct linger l; 254 struct linger l;
248 255
249 memset(&stAddr, 0, sizeof(stAddr)); 256 memset(&stAddr, 0, sizeof(stAddr));
250 stAddr.sin_family = AF_INET; 257 stAddr.sin_family = AF_INET;
251 stAddr.sin_port = htons(port); 258 stAddr.sin_port = htons(port);
252 259
253 if ((host = gethostbyname(address)) == NULL) 260 if ((host = gethostbyname(address)) == NULL) {
254 return (0); 261 return (0);
262 }
255 263
256 stAddr.sin_addr = *((struct in_addr *)host->h_addr_list[0]); 264 stAddr.sin_addr = *((struct in_addr *)host->h_addr_list[0]);
257 265
258 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 266 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
259 return (0); 267 return (0);
268 }
260 269
261 l.l_onoff = 1; 270 l.l_onoff = 1;
262 l.l_linger = 5; 271 l.l_linger = 5;
263 if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&l, sizeof(l)) < 0) 272 if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&l, sizeof(l)) < 0) {
264 return (0); 273 return (0);
274 }
265 275
266 if (connect(sock, (struct sockaddr *)&stAddr, sizeof(stAddr)) < 0) 276 if (connect(sock, (struct sockaddr *)&stAddr, sizeof(stAddr)) < 0) {
267 return (0); 277 return (0);
278 }
268 279
269 return (sock); 280 return (sock);
270} 281}
271 282
272 283
273/** 284/**
@@ -278,20 +289,18 @@ int LibMadPlugin::tcp_open(char *address, int port) {
278 * @param size size of the buffer 289 * @param size size of the buffer
279 * @return the size of the stream read or -1 if an error occured 290 * @return the size of the stream read or -1 if an error occured
280 */ 291 */
281int LibMadPlugin::http_read_line(int tcp_sock, char *buf, int size) { 292int LibMadPlugin::http_read_line(int tcp_sock, char *buf, int size) {
282 int offset = 0; 293 int offset = 0;
283 294
284 do 295 do {
285 {
286 if (std::read(tcp_sock, buf + offset, 1) < 0) 296 if (std::read(tcp_sock, buf + offset, 1) < 0)
287 return -1; 297 return -1;
288 if (buf[offset] != '\r') /* Strip \r from answer */ 298 if (buf[offset] != '\r') /* Strip \r from answer */
289 offset++; 299 offset++;
290 } 300 } while (offset < size - 1 && buf[offset - 1] != '\n');
291 while (offset < size - 1 && buf[offset - 1] != '\n');
292 301
293 buf[offset] = 0; 302 buf[offset] = 0;
294 return offset; 303 return offset;
295} 304}
296 305
297int LibMadPlugin::http_open(const QString& path ) { 306int LibMadPlugin::http_open(const QString& path ) {
@@ -302,111 +311,122 @@ int LibMadPlugin::http_open(const QString& path ) {
302 char http_request[PATH_MAX]; 311 char http_request[PATH_MAX];
303 char filename[PATH_MAX]; 312 char filename[PATH_MAX];
304 char c; 313 char c;
305 char *arg =strdup(path.latin1()); 314 char *arg =strdup(path.latin1());
306 315
307 /* Check for URL syntax */ 316 /* Check for URL syntax */
308 if (strncmp(arg, "http://", strlen("http://"))) 317 if (strncmp(arg, "http://", strlen("http://"))) {
309 return (0); 318 return (0);
319 }
310 320
311 /* Parse URL */ 321 /* Parse URL */
312 port = 80; 322 port = 80;
313 host = arg + strlen("http://"); 323 host = arg + strlen("http://");
314 if ((request = strchr(host, '/')) == NULL) 324 if ((request = strchr(host, '/')) == NULL) {
315 return (0); 325 return (0);
326 }
327
316 *request++ = 0; 328 *request++ = 0;
317 329
318 if (strchr(host, ':') != NULL) /* port is specified */ 330 if (strchr(host, ':') != NULL) { /* port is specified */
319 {
320 port = atoi(strchr(host, ':') + 1); 331 port = atoi(strchr(host, ':') + 1);
321 *strchr(host, ':') = 0; 332 *strchr(host, ':') = 0;
322 } 333 }
323 334
324 /* Open a TCP socket */ 335 /* Open a TCP socket */
325 if (!(tcp_sock = tcp_open(host, port))) 336 if (!(tcp_sock = tcp_open(host, port))) {
326 {
327 perror("http_open"); 337 perror("http_open");
328 return (0); 338 return (0);
329 } 339 }
330 340
331 snprintf(filename, sizeof(filename) - strlen(host) - 75, "%s", request); 341 snprintf(filename, sizeof(filename) - strlen(host) - 75, "%s", request);
332 342
333 /* Send HTTP GET request */ 343 /* Send HTTP GET request */
334 /* Please don't use a Agent know by shoutcast (Lynx, Mozilla) seems to be reconized and print 344 /* Please don't use a Agent know by shoutcast (Lynx, Mozilla) seems to be reconized and print
335 * a html page and not the stream */ 345 * a html page and not the stream */
336 snprintf(http_request, sizeof(http_request), "GET /%s HTTP/1.0\r\n" 346 snprintf(http_request, sizeof(http_request), "GET /%s HTTP/1.0\r\n"
337/* "User-Agent: Mozilla/2.0 (Win95; I)\r\n" */ 347 /* "User-Agent: Mozilla/2.0 (Win95; I)\r\n" */
338 "Pragma: no-cache\r\n" "Host: %s\r\n" "Accept: */*\r\n" "\r\n", filename, host); 348 "Pragma: no-cache\r\n" "Host: %s\r\n" "Accept: */*\r\n" "\r\n", filename, host);
339 349
340 send(tcp_sock, http_request, strlen(http_request), 0); 350 send(tcp_sock, http_request, strlen(http_request), 0);
341 351
342 /* Parse server reply */ 352 /* Parse server reply */
343#if 0 353#if 0
344 do 354 do
345 read(tcp_sock, &c, sizeof(char)); 355 read(tcp_sock, &c, sizeof(char));
346 while (c != ' '); 356 while (c != ' ');
347 read(tcp_sock, http_request, 4 * sizeof(char)); 357 read(tcp_sock, http_request, 4 * sizeof(char));
348 http_request[4] = 0; 358 http_request[4] = 0;
349 if (strcmp(http_request, "200 ")) 359 if (strcmp(http_request, "200 ")) {
350 {
351 fprintf(stderr, "http_open: "); 360 fprintf(stderr, "http_open: ");
352 do 361 do {
353 {
354 read(tcp_sock, &c, sizeof(char)); 362 read(tcp_sock, &c, sizeof(char));
355 fprintf(stderr, "%c", c); 363 fprintf(stderr, "%c", c);
356 } 364 } while (c != '\r');
357 while (c != '\r');
358 fprintf(stderr, "\n"); 365 fprintf(stderr, "\n");
359 return (0); 366 return (0);
360 } 367 }
361#endif 368#endif
362 369
363 do 370 QString name;
364 { 371 QString genre;
372 QString bitrate;
373 QString url;
374 QString message = tr("Info: ");
375
376 do {
377
365 int len; 378 int len;
366 379
367 len = http_read_line(tcp_sock, http_request, sizeof(http_request)); 380 len = http_read_line(tcp_sock, http_request, sizeof(http_request));
368 381
369 if (len == -1) 382 if (len == -1) {
370 {
371 fprintf(stderr, "http_open: %s\n", strerror(errno)); 383 fprintf(stderr, "http_open: %s\n", strerror(errno));
372 return 0; 384 return 0;
373 } 385 }
374 386
375 if (strncmp(http_request, "Location:", 9) == 0) 387 if (strncmp(http_request, "Location:", 9) == 0) {
376 {
377 /* redirect */ 388 /* redirect */
378 std::close(tcp_sock); 389 std::close(tcp_sock);
379 390
380 http_request[strlen(http_request) - 1] = '\0'; 391 http_request[strlen(http_request) - 1] = '\0';
381 392
382 return http_open(&http_request[10]); 393 return http_open(&http_request[10]);
383 } 394 }
384 395
385 if (strncmp(http_request, "ICY ", 4) == 0) 396 if (strncmp(http_request, "ICY ", 4) == 0) {
386 {
387 /* This is icecast streaming */ 397 /* This is icecast streaming */
388 if (strncmp(http_request + 4, "200 ", 4)) 398 if (strncmp(http_request + 4, "200 ", 4)) {
389 {
390 fprintf(stderr, "http_open: %s\n", http_request); 399 fprintf(stderr, "http_open: %s\n", http_request);
391 return 0; 400 return 0;
392 } 401 }
393 } 402 } else if (strncmp(http_request, "icy-", 4) == 0) {
394 else if (strncmp(http_request, "icy-", 4) == 0)
395 {
396 /* we can have: icy-noticeX, icy-name, icy-genre, icy-url, icy-pub, icy-metaint, icy-br */ 403 /* we can have: icy-noticeX, icy-name, icy-genre, icy-url, icy-pub, icy-metaint, icy-br */
397 /* Don't print these - mpg123 doesn't */ 404 if ( QString( http_request ).left( 8 ) == "icy-name" ) {
398 /* fprintf(stderr,"%s\n",http_request); */ 405 name = tr("Name: ") + QString(http_request).mid(9, (QString(http_request).length())- 9 );
406 } else if ( QString( http_request ).left( 9 ) == "icy-genre" ) {
407 genre = tr("Genre: ") + QString(http_request).mid(10, (QString(http_request).length())-10 );
408 } else if ( QString( http_request ).left( 6 ) == "icy-br" ) {
409 bitrate = tr("Bitrate: ") + QString(http_request).mid(7, (QString(http_request).length())- 7 );
410 } else if ( QString( http_request ).left( 7 ) == "icy-url" ) {
411 url = tr("URL: ") + QString(http_request).mid(8, (QString(http_request).length())- 8 );
412 } else if ( QString( http_request ).left( 10 ) == "icy-notice" ) {
413 message += QString(http_request).mid(11, QString(http_request).length()-11 ) ;
414 }
399 } 415 }
400 } 416 } while (strcmp(http_request, "\n") != 0);
401 while (strcmp(http_request, "\n") != 0); 417
418 info = QString(name + genre + url + bitrate + message).replace( QRegExp("\n"), " : " );
419
420 qDebug("Stream info: " + info);
402 421
403 return (tcp_sock); 422 return (tcp_sock);
404} 423}
405 424
406 425
426
407bool LibMadPlugin::open( const QString& path ) { 427bool LibMadPlugin::open( const QString& path ) {
408 debugMsg( "LibMadPlugin::open" ); 428 debugMsg( "LibMadPlugin::open" );
409 Config cfg("MediaPlayer"); 429 Config cfg("MediaPlayer");
410 cfg.setGroup("Options"); 430 cfg.setGroup("Options");
411 bufferSize = cfg.readNumEntry("MPeg_BufferSize",MPEG_BUFFER_SIZE); 431 bufferSize = cfg.readNumEntry("MPeg_BufferSize",MPEG_BUFFER_SIZE);
412 qDebug("buffer size is %d", bufferSize); 432 qDebug("buffer size is %d", bufferSize);
@@ -415,47 +435,51 @@ bool LibMadPlugin::open( const QString& path ) {
415 info = QString( "" ); 435 info = QString( "" );
416 436
417 //qDebug( "Opening %s", path.latin1() ); 437 //qDebug( "Opening %s", path.latin1() );
418 438
419 439
420 if (path.left( 4 ) == "http" ) { 440 if (path.left( 4 ) == "http" ) {
421 d->input.fd = http_open(path); 441 // in case of any error we get 0 here
422 442 if ( !(http_open(path)==0) ) {
443 d->input.fd = http_open(path);
444 }
423 } else { 445 } else {
424 d->input.path = path.latin1(); 446 d->input.path = path.latin1();
425 d->input.fd = ::open( d->input.path, O_RDONLY ); 447 d->input.fd = ::open( d->input.path, O_RDONLY );
448 // thats a better place, since it should only seek for ID3 tags on mp3 files, not streams
449 printID3Tags();
426 } 450 }
427 if (d->input.fd == -1) { 451 if (d->input.fd == -1) {
428 qDebug("error opening %s", d->input.path ); 452// qDebug("error opening %s", d->input.path );
429 return FALSE; 453 return FALSE;
430 } 454 }
431 455
432 printID3Tags(); 456// printID3Tags();
433 457
434#if defined(HAVE_MMAP) 458#if defined(HAVE_MMAP)
435 struct stat stat; 459 struct stat stat;
436 if (fstat(d->input.fd, &stat) == -1) { 460 if (fstat(d->input.fd, &stat) == -1) {
437 qDebug("error calling fstat"); return FALSE; 461 //qDebug("error calling fstat"); return FALSE;
438 } 462 }
439 if (S_ISREG(stat.st_mode) && stat.st_size > 0) { 463 if (S_ISREG(stat.st_mode) && stat.st_size > 0) {
440 d->input.length = stat.st_size; 464 d->input.length = stat.st_size;
441 d->input.fdm = map_file(d->input.fd, &d->input.length); 465 d->input.fdm = map_file(d->input.fd, &d->input.length);
442 if (d->input.fdm == 0) { 466 if (d->input.fdm == 0) {
443 qDebug("error mmapping file"); return FALSE; 467 qDebug("error mmapping file"); return FALSE;
444 } 468 }
445 d->input.data = (unsigned char *)d->input.fdm; 469 d->input.data = (unsigned char *)d->input.fdm;
446 } 470 }
447#endif 471#endif
448 472
449 if (d->input.data == 0) { 473 if (d->input.data == 0) {
450 d->input.data = (unsigned char *)malloc( bufferSize /*MPEG_BUFFER_SIZE*/); 474 d->input.data = (unsigned char *)malloc( bufferSize /*MPEG_BUFFER_SIZE*/);
451 if (d->input.data == 0) { 475 if (d->input.data == 0) {
452 qDebug("error allocating input buffer"); 476 qDebug("error allocating input buffer");
453 return FALSE; 477 return FALSE;
454 } 478 }
455 d->input.length = 0; 479 d->input.length = 0;
456 } 480 }
457 481
458 d->input.eof = 0; 482 d->input.eof = 0;
459 483
460 mad_stream_init(&d->stream); 484 mad_stream_init(&d->stream);
461 mad_frame_init(&d->frame); 485 mad_frame_init(&d->frame);
@@ -473,29 +497,29 @@ bool LibMadPlugin::close() {
473 mad_synth_finish(&d->synth); 497 mad_synth_finish(&d->synth);
474 mad_frame_finish(&d->frame); 498 mad_frame_finish(&d->frame);
475 mad_stream_finish(&d->stream); 499 mad_stream_finish(&d->stream);
476 500
477#if defined(HAVE_MMAP) 501#if defined(HAVE_MMAP)
478 if (d->input.fdm) { 502 if (d->input.fdm) {
479 if (unmap_file(d->input.fdm, d->input.length) == -1) { 503 if (unmap_file(d->input.fdm, d->input.length) == -1) {
480 qDebug("error munmapping file"); 504 qDebug("error munmapping file");
481 result = FALSE; 505 result = FALSE;
482 } 506 }
483 d->input.fdm = 0; 507 d->input.fdm = 0;
484 d->input.data = 0; 508 d->input.data = 0;
485 } 509 }
486#endif 510#endif
487 511
488 if (d->input.data) { 512 if (d->input.data) {
489 free(d->input.data); 513 free(d->input.data);
490 d->input.data = 0; 514 d->input.data = 0;
491 } 515 }
492 516
493 if (::close(d->input.fd) == -1) { 517 if (::close(d->input.fd) == -1) {
494 qDebug("error closing file %s", d->input.path); 518 qDebug("error closing file %s", d->input.path);
495 result = FALSE; 519 result = FALSE;
496 } 520 }
497 521
498 d->input.fd = 0; 522 d->input.fd = 0;
499 523
500 return result; 524 return result;
501} 525}
@@ -513,15 +537,15 @@ int LibMadPlugin::audioStreams() {
513} 537}
514 538
515 539
516int LibMadPlugin::audioChannels( int ) { 540int LibMadPlugin::audioChannels( int ) {
517 debugMsg( "LibMadPlugin::audioChannels" ); 541 debugMsg( "LibMadPlugin::audioChannels" );
518/* 542/*
519 long t; short t1[5]; audioReadSamples( t1, 2, 1, t, 0 ); 543 long t; short t1[5]; audioReadSamples( t1, 2, 1, t, 0 );
520 qDebug( "LibMadPlugin::audioChannels: %i", d->frame.header.mode > 0 ? 2 : 1 ); 544 qDebug( "LibMadPlugin::audioChannels: %i", d->frame.header.mode > 0 ? 2 : 1 );
521 return d->frame.header.mode > 0 ? 2 : 1; 545 return d->frame.header.mode > 0 ? 2 : 1;
522*/ 546*/
523 return 2; 547 return 2;
524} 548}
525 549
526 550
527int LibMadPlugin::audioFrequency( int ) { 551int LibMadPlugin::audioFrequency( int ) {
@@ -554,126 +578,124 @@ long LibMadPlugin::audioGetSample( int ) {
554 debugMsg( "LibMadPlugin::audioGetSample" ); 578 debugMsg( "LibMadPlugin::audioGetSample" );
555 return 0; 579 return 0;
556} 580}
557 581
558/* 582/*
559bool LibMadPlugin::audioReadSamples( short *, int, long, int ) { 583bool LibMadPlugin::audioReadSamples( short *, int, long, int ) {
560 debugMsg( "LibMadPlugin::audioReadSamples" ); 584debugMsg( "LibMadPlugin::audioReadSamples" );
561 return FALSE; 585return FALSE;
562} 586}
563 587
564 588
565bool LibMadPlugin::audioReReadSamples( short *, int, long, int ) { 589bool LibMadPlugin::audioReReadSamples( short *, int, long, int ) {
566 debugMsg( "LibMadPlugin::audioReReadSamples" ); 590debugMsg( "LibMadPlugin::audioReReadSamples" );
567 return FALSE; 591 return FALSE;
568} 592 }
569*/ 593*/
570 594
571bool LibMadPlugin::read() { 595bool LibMadPlugin::read() {
572 debugMsg( "LibMadPlugin::read" ); 596 debugMsg( "LibMadPlugin::read" );
573 int len; 597 int len;
574 598
575 if (d->input.eof) 599 if (d->input.eof)
576 return FALSE; 600 return FALSE;
577 601
578#if defined(HAVE_MMAP) 602#if defined(HAVE_MMAP)
579 if (d->input.fdm) { 603 if (d->input.fdm) {
580 unsigned long skip = 0; 604 unsigned long skip = 0;
581 605
582 if (d->stream.next_frame) { 606 if (d->stream.next_frame) {
583 struct stat stat; 607 struct stat stat;
584 608
585 if (fstat(d->input.fd, &stat) == -1) 609 if (fstat(d->input.fd, &stat) == -1)
586 return FALSE; 610 return FALSE;
587 611
588 if (stat.st_size + MAD_BUFFER_GUARD <= (signed)d->input.length) 612 if (stat.st_size + MAD_BUFFER_GUARD <= (signed)d->input.length)
589 return FALSE; 613 return FALSE;
590 614
591 // file size changed; update memory map 615 // file size changed; update memory map
592 skip = d->stream.next_frame - d->input.data; 616 skip = d->stream.next_frame - d->input.data;
593 617
594 if (unmap_file(d->input.fdm, d->input.length) == -1) { 618 if (unmap_file(d->input.fdm, d->input.length) == -1) {
595 d->input.fdm = 0; 619 d->input.fdm = 0;
596 d->input.data = 0; 620 d->input.data = 0;
597 return FALSE; 621 return FALSE;
598 } 622 }
599 623
600 d->input.length = stat.st_size; 624 d->input.length = stat.st_size;
601 625
602 d->input.fdm = map_file(d->input.fd, &d->input.length); 626 d->input.fdm = map_file(d->input.fd, &d->input.length);
603 if (d->input.fdm == 0) { 627 if (d->input.fdm == 0) {
604 d->input.data = 0; 628 d->input.data = 0;
605 return FALSE; 629 return FALSE;
606 } 630 }
607 631
608 d->input.data = (unsigned char *)d->input.fdm; 632 d->input.data = (unsigned char *)d->input.fdm;
609 } 633 }
610 634
611 mad_stream_buffer(&d->stream, d->input.data + skip, d->input.length - skip); 635 mad_stream_buffer(&d->stream, d->input.data + skip, d->input.length - skip);
612 636
613 } else 637 } else
614#endif 638#endif
615 { 639 {
616 if (d->stream.next_frame) { 640 if (d->stream.next_frame) {
617 memmove(d->input.data, d->stream.next_frame, 641 memmove(d->input.data, d->stream.next_frame,
618 d->input.length = &d->input.data[d->input.length] - d->stream.next_frame); 642 d->input.length = &d->input.data[d->input.length] - d->stream.next_frame);
619 } 643 }
620 644
621 do { 645 do {
622 len = ::read(d->input.fd, d->input.data + d->input.length, bufferSize /* MPEG_BUFFER_SIZE*/ - d->input.length); 646 len = ::read(d->input.fd, d->input.data + d->input.length, bufferSize /* MPEG_BUFFER_SIZE*/ - d->input.length);
623 } 647 }
624 while (len == -1 && errno == EINTR); 648 while (len == -1 && errno == EINTR);
625 649
626 if (len == -1) { 650 if (len == -1) {
627 qDebug("error reading audio"); 651 qDebug("error reading audio");
628 return FALSE; 652 return FALSE;
629 } 653 }
630 else if (len == 0) { 654 else if (len == 0) {
631 d->input.eof = 1; 655 d->input.eof = 1;
632 656
633 assert(bufferSize /*MPEG_BUFFER_SIZE*/ - d->input.length >= MAD_BUFFER_GUARD); 657 assert(bufferSize /*MPEG_BUFFER_SIZE*/ - d->input.length >= MAD_BUFFER_GUARD);
634 658
635 while (len < MAD_BUFFER_GUARD) 659 while (len < MAD_BUFFER_GUARD)
636 d->input.data[d->input.length + len++] = 0; 660 d->input.data[d->input.length + len++] = 0;
637 } 661 }
638 662
639 mad_stream_buffer(&d->stream, d->input.data, d->input.length += len); 663 mad_stream_buffer(&d->stream, d->input.data, d->input.length += len);
640 } 664 }
641 665
642 return TRUE; 666 return TRUE;
643} 667}
644 668
645 669
646static mad_fixed_t left_err, right_err; 670static mad_fixed_t left_err, right_err;
647static const int bits = 16; 671static const int bits = 16;
648static const int shift = MAD_F_FRACBITS + 1 - bits; 672static const int shift = MAD_F_FRACBITS + 1 - bits;
649 673
650 674
651inline long audio_linear_dither( mad_fixed_t sample, mad_fixed_t& error ) 675inline long audio_linear_dither( mad_fixed_t sample, mad_fixed_t& error ) {
652{
653 sample += error; 676 sample += error;
654 mad_fixed_t quantized = (sample >= MAD_F_ONE) ? MAD_F_ONE - 1 : ( (sample < -MAD_F_ONE) ? -MAD_F_ONE : sample ); 677 mad_fixed_t quantized = (sample >= MAD_F_ONE) ? MAD_F_ONE - 1 : ( (sample < -MAD_F_ONE) ? -MAD_F_ONE : sample );
655 quantized &= ~((1L << shift) - 1); 678 quantized &= ~((1L << shift) - 1);
656 error = sample - quantized; 679 error = sample - quantized;
657 return quantized >> shift; 680 return quantized >> shift;
658} 681}
659 682
660 683
661inline void audio_pcm( short *data, unsigned int nsamples, mad_fixed_t *left, mad_fixed_t *right ) 684inline void audio_pcm( short *data, unsigned int nsamples, mad_fixed_t *left, mad_fixed_t *right ) {
662{
663 if ( right ) { 685 if ( right ) {
664 while (nsamples--) { 686 while (nsamples--) {
665 data[0] = audio_linear_dither( *left++, left_err ); 687 data[0] = audio_linear_dither( *left++, left_err );
666 data[1] = audio_linear_dither( *right++, right_err ); 688 data[1] = audio_linear_dither( *right++, right_err );
667 data += 2; 689 data += 2;
668 } 690 }
669 } else { 691 } else {
670 while (nsamples--) { 692 while (nsamples--) {
671 data[0] = data[1] = audio_linear_dither( *left++, left_err ); 693 data[0] = data[1] = audio_linear_dither( *left++, left_err );
672 data += 2; 694 data += 2;
673 } 695 }
674 } 696 }
675} 697}
676 698
677 699
678bool LibMadPlugin::decode( short *output, long samples, long& samplesMade ) { 700bool LibMadPlugin::decode( short *output, long samples, long& samplesMade ) {
679 debugMsg( "LibMadPlugin::decode" ); 701 debugMsg( "LibMadPlugin::decode" );
@@ -682,99 +704,84 @@ bool LibMadPlugin::decode( short *output, long samples, long& samplesMade ) {
682 static mad_fixed_t buffer[2][65536 * 2]; 704 static mad_fixed_t buffer[2][65536 * 2];
683 int offset = buffered; 705 int offset = buffered;
684 samplesMade = 0; 706 samplesMade = 0;
685 707
686 static int maxBuffered = 8000; // 65536; 708 static int maxBuffered = 8000; // 65536;
687 709
688 if ( samples > maxBuffered ) 710 if ( samples > maxBuffered ) {
689 samples = maxBuffered; 711 samples = maxBuffered;
712 }
690 713
691 if ( d->flush ) { 714 if ( d->flush ) {
692 buffered = 0; 715 buffered = 0;
693 offset = 0; 716 offset = 0;
694 d->flush = FALSE; 717 d->flush = FALSE;
695 } 718 }
696 719
697 while ( buffered < maxBuffered ) { 720 while ( buffered < maxBuffered ) {
698 721
699 while (mad_frame_decode(&d->frame, &d->stream) == -1) { 722 while (mad_frame_decode(&d->frame, &d->stream) == -1) {
700 if (!MAD_RECOVERABLE(d->stream.error)) { 723 if (!MAD_RECOVERABLE(d->stream.error)) {
701 debugMsg( "feed me" ); 724 debugMsg( "feed me" );
702 return FALSE; // Feed me 725 return FALSE; // Feed me
703 } 726 }
704 if ( d->stream.error == MAD_ERROR_BADCRC ) { 727 if ( d->stream.error == MAD_ERROR_BADCRC ) {
705 mad_frame_mute(&d->frame); 728 mad_frame_mute(&d->frame);
706 qDebug( "error decoding, bad crc" ); 729 qDebug( "error decoding, bad crc" );
707 } 730 }
708 } 731 }
709 732
710 mad_synth_frame(&d->synth, &d->frame); 733 mad_synth_frame(&d->synth, &d->frame);
711 int decodedSamples = d->synth.pcm.length; 734 int decodedSamples = d->synth.pcm.length;
712 memcpy( &(buffer[0][offset]), d->synth.pcm.samples[0], decodedSamples * sizeof(mad_fixed_t) ); 735 memcpy( &(buffer[0][offset]), d->synth.pcm.samples[0], decodedSamples * sizeof(mad_fixed_t) );
713 if ( d->synth.pcm.channels == 2 ) 736 if ( d->synth.pcm.channels == 2 )
714 memcpy( &(buffer[1][offset]), d->synth.pcm.samples[1], decodedSamples * sizeof(mad_fixed_t) ); 737 memcpy( &(buffer[1][offset]), d->synth.pcm.samples[1], decodedSamples * sizeof(mad_fixed_t) );
715 offset += decodedSamples; 738 offset += decodedSamples;
716 buffered += decodedSamples; 739 buffered += decodedSamples;
717 } 740 }
741
718//qApp->processEvents(); 742//qApp->processEvents();
719 audio_pcm( output, samples, buffer[0], (d->synth.pcm.channels == 2) ? buffer[1] : 0 ); 743 audio_pcm( output, samples, buffer[0], (d->synth.pcm.channels == 2) ? buffer[1] : 0 );
720// audio_pcm( output, samples, buffer[1], buffer[0] ); 744// audio_pcm( output, samples, buffer[1], buffer[0] );
721// audio_pcm( output, samples, buffer[0], buffer[1] ); 745// audio_pcm( output, samples, buffer[0], buffer[1] );
722 samplesMade = samples; 746 samplesMade = samples;
723 memmove( buffer[0], &(buffer[0][samples]), (buffered - samples) * sizeof(mad_fixed_t) ); 747 memmove( buffer[0], &(buffer[0][samples]), (buffered - samples) * sizeof(mad_fixed_t) );
724 if ( d->synth.pcm.channels == 2 ) 748 if ( d->synth.pcm.channels == 2 ) {
725 memmove( buffer[1], &(buffer[1][samples]), (buffered - samples) * sizeof(mad_fixed_t) ); 749 memmove( buffer[1], &(buffer[1][samples]), (buffered - samples) * sizeof(mad_fixed_t) );
750 }
726 buffered -= samples; 751 buffered -= samples;
727 752
728 return TRUE; 753 return TRUE;
729} 754}
730 755
731/* 756/*bool LibMadPlugin::audioReadStereoSamples( short *output, long samples, long& samplesMade, int ) {
732bool LibMadPlugin::audioReadMonoSamples( short *, long, long&, int ) {
733 debugMsg( "LibMadPlugin::audioReadMonoSamples" );
734 return FALSE;
735}
736
737
738bool LibMadPlugin::audioReadStereoSamples( short *output, long samples, long& samplesMade, int ) {
739*/ 757*/
740bool LibMadPlugin::audioReadSamples( short *output, int /*channels*/, long samples, long& samplesMade, int ) { 758bool LibMadPlugin::audioReadSamples( short *output, int /*channels*/, long samples, long& samplesMade, int ) {
741 debugMsg( "LibMadPlugin::audioReadStereoSamples" ); 759 debugMsg( "LibMadPlugin::audioReadStereoSamples" );
742 760
743 static bool needInput = TRUE; 761 static bool needInput = TRUE;
744 762
745 if ( samples == 0 ) 763 if ( samples == 0 )
746 return FALSE; 764 return FALSE;
747 765
748 do { 766 do {
749 if ( needInput ) 767 if ( needInput )
750 if ( !read() ) { 768 if ( !read() ) {
751// if ( d->input.eof ) 769 return FALSE;
752// needInput = FALSE; 770 }
753// else
754 return FALSE;
755 }
756 771
757 needInput = FALSE; 772 needInput = FALSE;
758 773
759 if ( decode( output, samples, samplesMade ) ) 774 if ( decode( output, samples, samplesMade ) )
760 return TRUE; 775 return TRUE;
761 else 776 else
762 needInput = TRUE; 777 needInput = TRUE;
763 } 778 }
764 while ( ( samplesMade < samples ) && ( !d->input.eof ) ); 779 while ( ( samplesMade < samples ) && ( !d->input.eof ) );
765/*
766 static bool firstTimeThru = TRUE;
767 780
768 if ( firstTimeThru ) { 781 return FALSE;
769 firstTimeThru = FALSE;
770 decode( output, samples, samplesMade );
771 return FALSE;
772 } else
773*/
774 return FALSE;
775} 782}
776 783
777 784
778double LibMadPlugin::getTime() { 785double LibMadPlugin::getTime() {
779 debugMsg( "LibMadPlugin::getTime" ); 786 debugMsg( "LibMadPlugin::getTime" );
780 return 0.0; 787 return 0.0;
@@ -784,45 +791,45 @@ double LibMadPlugin::getTime() {
784void LibMadPlugin::printID3Tags() { 791void LibMadPlugin::printID3Tags() {
785 qDebug( "LibMadPlugin::printID3Tags" ); 792 qDebug( "LibMadPlugin::printID3Tags" );
786 793
787 char id3v1[128 + 1]; 794 char id3v1[128 + 1];
788 795
789 if ( ::lseek( d->input.fd, -128, SEEK_END ) == -1 ) { 796 if ( ::lseek( d->input.fd, -128, SEEK_END ) == -1 ) {
790 qDebug( "error seeking to id3 tags" ); 797 qDebug( "error seeking to id3 tags" );
791 return; 798 return;
792 } 799 }
793 800
794 if ( ::read( d->input.fd, id3v1, 128 ) != 128 ) { 801 if ( ::read( d->input.fd, id3v1, 128 ) != 128 ) {
795 qDebug( "error reading in id3 tags" ); 802 qDebug( "error reading in id3 tags" );
796 return; 803 return;
797 } 804 }
798 805
799 if ( ::strncmp( (const char *)id3v1, "TAG", 3 ) != 0 ) { 806 if ( ::strncmp( (const char *)id3v1, "TAG", 3 ) != 0 ) {
800 debugMsg( "sorry, no id3 tags" ); 807 debugMsg( "sorry, no id3 tags" );
801 } else { 808 } else {
802 int len[5] = { 30, 30, 30, 4, 30 }; 809 int len[5] = { 30, 30, 30, 4, 30 };
803 QString label[5] = { tr( "Title" ), tr( "Artist" ), tr( "Album" ), tr( "Year" ), tr( "Comment" ) }; 810 QString label[5] = { tr( "Title" ), tr( "Artist" ), tr( "Album" ), tr( "Year" ), tr( "Comment" ) };
804 char *ptr = id3v1 + 3, *ptr2 = ptr + len[0]; 811 char *ptr = id3v1 + 3, *ptr2 = ptr + len[0];
805 qDebug( "ID3 tags in file:" ); 812 qDebug( "ID3 tags in file:" );
806 info = ""; 813 info = "";
807 for ( int i = 0; i < 5; ptr += len[i], i++, ptr2 += len[i] ) { 814 for ( int i = 0; i < 5; ptr += len[i], i++, ptr2 += len[i] ) {
808 char push = *ptr2; 815 char push = *ptr2;
809 *ptr2 = '\0'; 816 *ptr2 = '\0';
810 char *ptr3 = ptr2; 817 char *ptr3 = ptr2;
811 while ( ptr3-1 >= ptr && isspace(ptr3[-1]) ) ptr3--; 818 while ( ptr3-1 >= ptr && isspace(ptr3[-1]) ) ptr3--;
812 char push2 = *ptr3; *ptr3 = '\0'; 819 char push2 = *ptr3; *ptr3 = '\0';
813 if ( strcmp( ptr, "" ) ) 820 if ( strcmp( ptr, "" ) )
814 info += ( i != 0 ? ", " : "" ) + label[i] + ": " + ptr; 821 info += ( i != 0 ? ", " : "" ) + label[i] + ": " + ptr;
815 //qDebug( info.latin1() ); 822 //qDebug( info.latin1() );
816 *ptr3 = push2; 823 *ptr3 = push2;
817 *ptr2 = push; 824 *ptr2 = push;
818 } 825 }
819 if (id3v1[126] == 0 && id3v1[127] != 0) 826 if (id3v1[126] == 0 && id3v1[127] != 0)
820 info += tr( ", Track: " ) + id3v1[127]; 827 info += tr( ", Track: " ) + id3v1[127];
821 } 828 }
822 829
823 if ( ::lseek(d->input.fd, 0, SEEK_SET) == -1 ) { 830 if ( ::lseek(d->input.fd, 0, SEEK_SET) == -1 ) {
824 qDebug( "error seeking back to beginning" ); 831 qDebug( "error seeking back to beginning" );
825 return; 832 return;
826 } 833 }
827} 834}
828 835