author | harlekin <harlekin> | 2002-04-22 21:47:09 (UTC) |
---|---|---|
committer | harlekin <harlekin> | 2002-04-22 21:47:09 (UTC) |
commit | f77f012023dbe7582a4b4297f61c6521ad8a3aa5 (patch) (side-by-side diff) | |
tree | 3d41a0320169e8b2749e7cee98f14e0435fe05e3 /core | |
parent | cca7f8ae4f60ae9b6c704d200ab015233abdd4d7 (diff) | |
download | opie-f77f012023dbe7582a4b4297f61c6521ad8a3aa5.zip opie-f77f012023dbe7582a4b4297f61c6521ad8a3aa5.tar.gz opie-f77f012023dbe7582a4b4297f61c6521ad8a3aa5.tar.bz2 |
get shoutcast support better, now all stream information are shown in the mediaplayer
-rw-r--r-- | core/multimedia/opieplayer/libmad/libmadplugin.cpp | 159 |
1 files changed, 83 insertions, 76 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 @@ -8,39 +8,44 @@ ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ +// largly modified by Maximilian Reiss <max.reiss@gmx.de> + #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <time.h> #include <locale.h> #include <math.h> #include <assert.h> + #include <qapplication.h> +#include <qmessagebox.h> + #include <qpe/config.h> // for network handling #include <netinet/in.h> #include <netdb.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> //#define HAVE_MMAP @@ -189,261 +194,280 @@ int LibMadPlugin::is_address_multicast(unsigned long address) { int LibMadPlugin::udp_open(char *address, int port) { int enable = 1L; struct sockaddr_in stAddr; struct sockaddr_in stLclAddr; struct ip_mreq stMreq; struct hostent *host; int sock; stAddr.sin_family = AF_INET; stAddr.sin_port = htons(port); - if ((host = gethostbyname(address)) == NULL) + if ((host = gethostbyname(address)) == NULL) { return (0); + } stAddr.sin_addr = *((struct in_addr *)host->h_addr_list[0]); /* Create a UDP socket */ - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { return (0); + } /* Allow multiple instance of the client to share the same address and port */ - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&enable, sizeof(unsigned long int)) < 0) + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&enable, sizeof(unsigned long int)) < 0) { return (0); + } /* If the address is multicast, register to the multicast group */ - if (is_address_multicast(stAddr.sin_addr.s_addr)) - { + if (is_address_multicast(stAddr.sin_addr.s_addr)) { /* Bind the socket to port */ stLclAddr.sin_family = AF_INET; stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); stLclAddr.sin_port = stAddr.sin_port; - if (bind(sock, (struct sockaddr *)&stLclAddr, sizeof(stLclAddr)) < 0) + if (bind(sock, (struct sockaddr *)&stLclAddr, sizeof(stLclAddr)) < 0) { return (0); + } /* Register to a multicast address */ stMreq.imr_multiaddr.s_addr = stAddr.sin_addr.s_addr; stMreq.imr_interface.s_addr = INADDR_ANY; - if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq)) < 0) + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq)) < 0) { return (0); } - else - { + } else { /* Bind the socket to port */ stLclAddr.sin_family = AF_INET; stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); stLclAddr.sin_port = htons(0); - if (bind(sock, (struct sockaddr *)&stLclAddr, sizeof(stLclAddr)) < 0) + if (bind(sock, (struct sockaddr *)&stLclAddr, sizeof(stLclAddr)) < 0) { return (0); } - + } return (sock); } int LibMadPlugin::tcp_open(char *address, int port) { struct sockaddr_in stAddr; struct hostent *host; int sock; struct linger l; memset(&stAddr, 0, sizeof(stAddr)); stAddr.sin_family = AF_INET; stAddr.sin_port = htons(port); - if ((host = gethostbyname(address)) == NULL) + if ((host = gethostbyname(address)) == NULL) { return (0); + } stAddr.sin_addr = *((struct in_addr *)host->h_addr_list[0]); - if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { return (0); + } l.l_onoff = 1; l.l_linger = 5; - if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&l, sizeof(l)) < 0) + if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&l, sizeof(l)) < 0) { return (0); + } - if (connect(sock, (struct sockaddr *)&stAddr, sizeof(stAddr)) < 0) + if (connect(sock, (struct sockaddr *)&stAddr, sizeof(stAddr)) < 0) { return (0); + } return (sock); } /** * Read a http line header. * This function read character by character. * @param tcp_sock the socket use to read the stream * @param buf a buffer to receive the data * @param size size of the buffer * @return the size of the stream read or -1 if an error occured */ int LibMadPlugin::http_read_line(int tcp_sock, char *buf, int size) { int offset = 0; - do - { + do { if (std::read(tcp_sock, buf + offset, 1) < 0) return -1; if (buf[offset] != '\r') /* Strip \r from answer */ offset++; - } - while (offset < size - 1 && buf[offset - 1] != '\n'); + } while (offset < size - 1 && buf[offset - 1] != '\n'); buf[offset] = 0; return offset; } int LibMadPlugin::http_open(const QString& path ) { char *host; int port; char *request; int tcp_sock; char http_request[PATH_MAX]; char filename[PATH_MAX]; char c; char *arg =strdup(path.latin1()); /* Check for URL syntax */ - if (strncmp(arg, "http://", strlen("http://"))) + if (strncmp(arg, "http://", strlen("http://"))) { return (0); + } /* Parse URL */ port = 80; host = arg + strlen("http://"); - if ((request = strchr(host, '/')) == NULL) + if ((request = strchr(host, '/')) == NULL) { return (0); + } + *request++ = 0; - if (strchr(host, ':') != NULL) /* port is specified */ - { + if (strchr(host, ':') != NULL) { /* port is specified */ port = atoi(strchr(host, ':') + 1); *strchr(host, ':') = 0; } /* Open a TCP socket */ - if (!(tcp_sock = tcp_open(host, port))) - { + if (!(tcp_sock = tcp_open(host, port))) { perror("http_open"); return (0); } snprintf(filename, sizeof(filename) - strlen(host) - 75, "%s", request); /* Send HTTP GET request */ /* Please don't use a Agent know by shoutcast (Lynx, Mozilla) seems to be reconized and print * a html page and not the stream */ snprintf(http_request, sizeof(http_request), "GET /%s HTTP/1.0\r\n" /* "User-Agent: Mozilla/2.0 (Win95; I)\r\n" */ "Pragma: no-cache\r\n" "Host: %s\r\n" "Accept: */*\r\n" "\r\n", filename, host); send(tcp_sock, http_request, strlen(http_request), 0); /* Parse server reply */ #if 0 do read(tcp_sock, &c, sizeof(char)); while (c != ' '); read(tcp_sock, http_request, 4 * sizeof(char)); http_request[4] = 0; - if (strcmp(http_request, "200 ")) - { + if (strcmp(http_request, "200 ")) { fprintf(stderr, "http_open: "); - do - { + do { read(tcp_sock, &c, sizeof(char)); fprintf(stderr, "%c", c); - } - while (c != '\r'); + } while (c != '\r'); fprintf(stderr, "\n"); return (0); } #endif - do - { + QString name; + QString genre; + QString bitrate; + QString url; + QString message = tr("Info: "); + + do { + int len; len = http_read_line(tcp_sock, http_request, sizeof(http_request)); - if (len == -1) - { + if (len == -1) { fprintf(stderr, "http_open: %s\n", strerror(errno)); return 0; } - if (strncmp(http_request, "Location:", 9) == 0) - { + if (strncmp(http_request, "Location:", 9) == 0) { /* redirect */ std::close(tcp_sock); http_request[strlen(http_request) - 1] = '\0'; return http_open(&http_request[10]); } - if (strncmp(http_request, "ICY ", 4) == 0) - { + if (strncmp(http_request, "ICY ", 4) == 0) { /* This is icecast streaming */ - if (strncmp(http_request + 4, "200 ", 4)) - { + if (strncmp(http_request + 4, "200 ", 4)) { fprintf(stderr, "http_open: %s\n", http_request); return 0; } - } - else if (strncmp(http_request, "icy-", 4) == 0) - { + } else if (strncmp(http_request, "icy-", 4) == 0) { /* we can have: icy-noticeX, icy-name, icy-genre, icy-url, icy-pub, icy-metaint, icy-br */ - /* Don't print these - mpg123 doesn't */ - /* fprintf(stderr,"%s\n",http_request); */ + if ( QString( http_request ).left( 8 ) == "icy-name" ) { + name = tr("Name: ") + QString(http_request).mid(9, (QString(http_request).length())- 9 ); + } else if ( QString( http_request ).left( 9 ) == "icy-genre" ) { + genre = tr("Genre: ") + QString(http_request).mid(10, (QString(http_request).length())-10 ); + } else if ( QString( http_request ).left( 6 ) == "icy-br" ) { + bitrate = tr("Bitrate: ") + QString(http_request).mid(7, (QString(http_request).length())- 7 ); + } else if ( QString( http_request ).left( 7 ) == "icy-url" ) { + url = tr("URL: ") + QString(http_request).mid(8, (QString(http_request).length())- 8 ); + } else if ( QString( http_request ).left( 10 ) == "icy-notice" ) { + message += QString(http_request).mid(11, QString(http_request).length()-11 ) ; } } - while (strcmp(http_request, "\n") != 0); + } while (strcmp(http_request, "\n") != 0); + + info = QString(name + genre + url + bitrate + message).replace( QRegExp("\n"), " : " ); + + qDebug("Stream info: " + info); return (tcp_sock); } + bool LibMadPlugin::open( const QString& path ) { debugMsg( "LibMadPlugin::open" ); Config cfg("MediaPlayer"); cfg.setGroup("Options"); bufferSize = cfg.readNumEntry("MPeg_BufferSize",MPEG_BUFFER_SIZE); qDebug("buffer size is %d", bufferSize); d->bad_last_frame = 0; d->flush = TRUE; info = QString( "" ); //qDebug( "Opening %s", path.latin1() ); if (path.left( 4 ) == "http" ) { + // in case of any error we get 0 here + if ( !(http_open(path)==0) ) { d->input.fd = http_open(path); - + } } else { d->input.path = path.latin1(); d->input.fd = ::open( d->input.path, O_RDONLY ); + // thats a better place, since it should only seek for ID3 tags on mp3 files, not streams + printID3Tags(); } if (d->input.fd == -1) { - qDebug("error opening %s", d->input.path ); +// qDebug("error opening %s", d->input.path ); return FALSE; } - printID3Tags(); +// printID3Tags(); #if defined(HAVE_MMAP) struct stat stat; if (fstat(d->input.fd, &stat) == -1) { - qDebug("error calling fstat"); return FALSE; + //qDebug("error calling fstat"); return FALSE; } if (S_ISREG(stat.st_mode) && stat.st_size > 0) { d->input.length = stat.st_size; d->input.fdm = map_file(d->input.fd, &d->input.length); if (d->input.fdm == 0) { qDebug("error mmapping file"); return FALSE; } d->input.data = (unsigned char *)d->input.fdm; } #endif if (d->input.data == 0) { @@ -639,36 +663,34 @@ bool LibMadPlugin::read() { mad_stream_buffer(&d->stream, d->input.data, d->input.length += len); } return TRUE; } static mad_fixed_t left_err, right_err; static const int bits = 16; static const int shift = MAD_F_FRACBITS + 1 - bits; -inline long audio_linear_dither( mad_fixed_t sample, mad_fixed_t& error ) -{ +inline long audio_linear_dither( mad_fixed_t sample, mad_fixed_t& error ) { sample += error; mad_fixed_t quantized = (sample >= MAD_F_ONE) ? MAD_F_ONE - 1 : ( (sample < -MAD_F_ONE) ? -MAD_F_ONE : sample ); quantized &= ~((1L << shift) - 1); error = sample - quantized; return quantized >> shift; } -inline void audio_pcm( short *data, unsigned int nsamples, mad_fixed_t *left, mad_fixed_t *right ) -{ +inline void audio_pcm( short *data, unsigned int nsamples, mad_fixed_t *left, mad_fixed_t *right ) { if ( right ) { while (nsamples--) { data[0] = audio_linear_dither( *left++, left_err ); data[1] = audio_linear_dither( *right++, right_err ); data += 2; } } else { while (nsamples--) { data[0] = data[1] = audio_linear_dither( *left++, left_err ); data += 2; } } @@ -676,26 +698,27 @@ inline void audio_pcm( short *data, unsigned int nsamples, mad_fixed_t *left, ma bool LibMadPlugin::decode( short *output, long samples, long& samplesMade ) { debugMsg( "LibMadPlugin::decode" ); static int buffered = 0; static mad_fixed_t buffer[2][65536 * 2]; int offset = buffered; samplesMade = 0; static int maxBuffered = 8000; // 65536; - if ( samples > maxBuffered ) + if ( samples > maxBuffered ) { samples = maxBuffered; + } if ( d->flush ) { buffered = 0; offset = 0; d->flush = FALSE; } while ( buffered < maxBuffered ) { while (mad_frame_decode(&d->frame, &d->stream) == -1) { if (!MAD_RECOVERABLE(d->stream.error)) { debugMsg( "feed me" ); @@ -706,80 +729,64 @@ bool LibMadPlugin::decode( short *output, long samples, long& samplesMade ) { qDebug( "error decoding, bad crc" ); } } mad_synth_frame(&d->synth, &d->frame); int decodedSamples = d->synth.pcm.length; memcpy( &(buffer[0][offset]), d->synth.pcm.samples[0], decodedSamples * sizeof(mad_fixed_t) ); if ( d->synth.pcm.channels == 2 ) memcpy( &(buffer[1][offset]), d->synth.pcm.samples[1], decodedSamples * sizeof(mad_fixed_t) ); offset += decodedSamples; buffered += decodedSamples; } + //qApp->processEvents(); audio_pcm( output, samples, buffer[0], (d->synth.pcm.channels == 2) ? buffer[1] : 0 ); // audio_pcm( output, samples, buffer[1], buffer[0] ); // audio_pcm( output, samples, buffer[0], buffer[1] ); samplesMade = samples; memmove( buffer[0], &(buffer[0][samples]), (buffered - samples) * sizeof(mad_fixed_t) ); - if ( d->synth.pcm.channels == 2 ) + if ( d->synth.pcm.channels == 2 ) { memmove( buffer[1], &(buffer[1][samples]), (buffered - samples) * sizeof(mad_fixed_t) ); + } buffered -= samples; return TRUE; } -/* -bool LibMadPlugin::audioReadMonoSamples( short *, long, long&, int ) { - debugMsg( "LibMadPlugin::audioReadMonoSamples" ); - return FALSE; -} - - -bool LibMadPlugin::audioReadStereoSamples( short *output, long samples, long& samplesMade, int ) { +/*bool LibMadPlugin::audioReadStereoSamples( short *output, long samples, long& samplesMade, int ) { */ bool LibMadPlugin::audioReadSamples( short *output, int /*channels*/, long samples, long& samplesMade, int ) { debugMsg( "LibMadPlugin::audioReadStereoSamples" ); static bool needInput = TRUE; if ( samples == 0 ) return FALSE; do { if ( needInput ) if ( !read() ) { -// if ( d->input.eof ) -// needInput = FALSE; -// else return FALSE; } needInput = FALSE; if ( decode( output, samples, samplesMade ) ) return TRUE; else needInput = TRUE; } while ( ( samplesMade < samples ) && ( !d->input.eof ) ); -/* - static bool firstTimeThru = TRUE; - if ( firstTimeThru ) { - firstTimeThru = FALSE; - decode( output, samples, samplesMade ); - return FALSE; - } else -*/ return FALSE; } double LibMadPlugin::getTime() { debugMsg( "LibMadPlugin::getTime" ); return 0.0; } void LibMadPlugin::printID3Tags() { qDebug( "LibMadPlugin::printID3Tags" ); |