summaryrefslogtreecommitdiff
authorharlekin <harlekin>2002-04-22 22:05:28 (UTC)
committer harlekin <harlekin>2002-04-22 22:05:28 (UTC)
commit1ce5e1128e3c062d45e6dcfbcda20f195b4d5b13 (patch) (side-by-side diff)
tree81303ba33d6f6aa7e56b9ea6ff6d85a7a894ede0
parentf77f012023dbe7582a4b4297f61c6521ad8a3aa5 (diff)
downloadopie-1ce5e1128e3c062d45e6dcfbcda20f195b4d5b13.zip
opie-1ce5e1128e3c062d45e6dcfbcda20f195b4d5b13.tar.gz
opie-1ce5e1128e3c062d45e6dcfbcda20f195b4d5b13.tar.bz2
more updates for shoutcast
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/libmad/libmadplugin.cpp17
1 files changed, 7 insertions, 10 deletions
diff --git a/core/multimedia/opieplayer/libmad/libmadplugin.cpp b/core/multimedia/opieplayer/libmad/libmadplugin.cpp
index 0f952f4..8b692ef 100644
--- a/core/multimedia/opieplayer/libmad/libmadplugin.cpp
+++ b/core/multimedia/opieplayer/libmad/libmadplugin.cpp
@@ -121,474 +121,471 @@ static int unmap_file(void *fdm, unsigned long length)
static inline QString tr( const char *str ) {
// Apparently this is okay from a plugin as it runs in the process space of the owner of the plugin
return qApp->translate( "OpiePlayer", str, "libmad strings for mp3 file info" );
}
class LibMadPluginData {
public:
Input input;
Output output;
int bad_last_frame;
struct mad_stream stream;
struct mad_frame frame;
struct mad_synth synth;
bool flush;
};
LibMadPlugin::LibMadPlugin() {
d = new LibMadPluginData;
d->input.fd = 0;
#if defined(HAVE_MMAP)
d->input.fdm = 0;
#endif
d->input.data = 0;
d->flush = TRUE;
info = tr( "No Song Open" );
}
LibMadPlugin::~LibMadPlugin() {
close();
delete d;
}
bool LibMadPlugin::isFileSupported( const QString& path ) {
debugMsg( "LibMadPlugin::isFileSupported" );
// Mpeg file extensions
// "mp2","mp3","m1v","m2v","m2s","mpg","vob","mpeg","ac3"
// Other media extensions
// "wav","mid","mod","s3m","ogg","avi","mov","sid"
char *ext = strrchr( path.latin1(), '.' );
// Test file extension
if ( ext ) {
if ( strncasecmp(ext, ".mp2", 4) == 0 )
return TRUE;
if ( strncasecmp(ext, ".mp3", 4) == 0 )
return TRUE;
}
// UGLY - just for fast testing
if ( path.left(4) == "http") {
return TRUE;
}
return FALSE;
}
int LibMadPlugin::is_address_multicast(unsigned long address) {
if ((address & 255) >= 224 && (address & 255) <= 239)
return (1);
return (0);
}
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) {
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) {
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) {
return (0);
}
/* If the address is multicast, register to the multicast group */
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) {
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) {
return (0);
}
} 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) {
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) {
return (0);
}
stAddr.sin_addr = *((struct in_addr *)host->h_addr_list[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) {
return (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 {
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');
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 c;
char *arg =strdup(path.latin1());
/* Check for URL syntax */
if (strncmp(arg, "http://", strlen("http://"))) {
return (0);
}
/* Parse URL */
port = 80;
host = arg + strlen("http://");
if ((request = strchr(host, '/')) == NULL) {
return (0);
}
*request++ = 0;
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))) {
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 ")) {
fprintf(stderr, "http_open: ");
do {
read(tcp_sock, &c, sizeof(char));
fprintf(stderr, "%c", c);
} while (c != '\r');
fprintf(stderr, "\n");
return (0);
}
#endif
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) {
- fprintf(stderr, "http_open: %s\n", strerror(errno));
+ qDebug( "http_open: "+ QString(strerror(errno)) +"\n");
return 0;
}
- if (strncmp(http_request, "Location:", 9) == 0) {
+ if (QString(http_request).left(9) == "Location:") {
/* 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) {
- /* This is icecast streaming */
+ if (QString(http_request).left(4) == "ICY ") {
+ /* This is shoutcast/icecast streaming */
if (strncmp(http_request + 4, "200 ", 4)) {
- fprintf(stderr, "http_open: %s\n", http_request);
+ qDebug("http_open: " + QString(http_request) + "\n");
return 0;
}
- } else if (strncmp(http_request, "icy-", 4) == 0) {
+ } else if (QString(http_request).left(4) == "icy-") {
/* we can have: icy-noticeX, icy-name, icy-genre, icy-url, icy-pub, icy-metaint, icy-br */
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);
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 );
return FALSE;
}
// printID3Tags();
#if defined(HAVE_MMAP)
struct stat stat;
if (fstat(d->input.fd, &stat) == -1) {
//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) {
d->input.data = (unsigned char *)malloc( bufferSize /*MPEG_BUFFER_SIZE*/);
if (d->input.data == 0) {
qDebug("error allocating input buffer");
return FALSE;
}
d->input.length = 0;
}
d->input.eof = 0;
mad_stream_init(&d->stream);
mad_frame_init(&d->frame);
mad_synth_init(&d->synth);
return TRUE;
}
bool LibMadPlugin::close() {
debugMsg( "LibMadPlugin::close" );
int result = TRUE;
mad_synth_finish(&d->synth);
mad_frame_finish(&d->frame);
mad_stream_finish(&d->stream);
#if defined(HAVE_MMAP)
if (d->input.fdm) {
if (unmap_file(d->input.fdm, d->input.length) == -1) {
qDebug("error munmapping file");
result = FALSE;
}
d->input.fdm = 0;
d->input.data = 0;
}
#endif
if (d->input.data) {
free(d->input.data);
d->input.data = 0;
}
if (::close(d->input.fd) == -1) {
qDebug("error closing file %s", d->input.path);
result = FALSE;
}
d->input.fd = 0;
return result;
}
bool LibMadPlugin::isOpen() {
debugMsg( "LibMadPlugin::isOpen" );
return ( d->input.fd != 0 );
}
int LibMadPlugin::audioStreams() {
debugMsg( "LibMadPlugin::audioStreams" );
return 1;
}
int LibMadPlugin::audioChannels( int ) {
debugMsg( "LibMadPlugin::audioChannels" );
/*
long t; short t1[5]; audioReadSamples( t1, 2, 1, t, 0 );
qDebug( "LibMadPlugin::audioChannels: %i", d->frame.header.mode > 0 ? 2 : 1 );
return d->frame.header.mode > 0 ? 2 : 1;
*/
return 2;
}
int LibMadPlugin::audioFrequency( int ) {
debugMsg( "LibMadPlugin::audioFrequency" );
long t; short t1[5]; audioReadSamples( t1, 2, 1, t, 0 );
qDebug( "LibMadPlugin::audioFrequency: %i", d->frame.header.samplerate );
return d->frame.header.samplerate;
}
int LibMadPlugin::audioSamples( int ) {
debugMsg( "LibMadPlugin::audioSamples" );
// long t; short t1[5]; audioReadSamples( t1, 2, 1, t, 0 );
// mad_header_decode( (struct mad_header *)&d->frame.header, &d->stream );
// qDebug( "LibMadPlugin::audioSamples: %i*%i", d->frame.header.duration.seconds, d->frame.header.samplerate );
// return d->frame.header.duration.seconds * d->frame.header.samplerate;
return 10000000;
}
bool LibMadPlugin::audioSetSample( long, int ) {
debugMsg( "LibMadPlugin::audioSetSample" );
return FALSE;
}
long LibMadPlugin::audioGetSample( int ) {
debugMsg( "LibMadPlugin::audioGetSample" );
return 0;
}
/*
bool LibMadPlugin::audioReadSamples( short *, int, long, int ) {
debugMsg( "LibMadPlugin::audioReadSamples" );
return FALSE;
}
bool LibMadPlugin::audioReReadSamples( short *, int, long, int ) {
debugMsg( "LibMadPlugin::audioReReadSamples" );
return FALSE;
}
*/