summaryrefslogtreecommitdiff
Side-by-side diff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--core/multimedia/opieplayer/libmad/libmadplugin.cpp159
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" );