ogg stream playing! some non-blocking seek bug fixes
git-svn-id: https://svn.musicpd.org/mpd/trunk@1105 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
parent
5a4022d878
commit
4db5224b47
86
src/decode.c
86
src/decode.c
@ -89,6 +89,7 @@ void stopDecode(DecoderControl * dc) {
|
|||||||
void quitDecode(PlayerControl * pc, DecoderControl * dc) {
|
void quitDecode(PlayerControl * pc, DecoderControl * dc) {
|
||||||
stopDecode(dc);
|
stopDecode(dc);
|
||||||
pc->state = PLAYER_STATE_STOP;
|
pc->state = PLAYER_STATE_STOP;
|
||||||
|
dc->seek = 0;
|
||||||
pc->play = 0;
|
pc->play = 0;
|
||||||
pc->stop = 0;
|
pc->stop = 0;
|
||||||
pc->pause = 0;
|
pc->pause = 0;
|
||||||
@ -113,23 +114,34 @@ int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define handleDecodeStart() \
|
#define handleDecodeStart() \
|
||||||
if(decodeWaitedOn && dc->state==DECODE_STATE_DECODE) { \
|
if(decodeWaitedOn) { \
|
||||||
decodeWaitedOn = 0; \
|
if(dc->state!=DECODE_STATE_START && *decode_pid > 0 && \
|
||||||
if(openAudioDevice(&(cb->audioFormat))<0) { \
|
dc->error==DECODE_ERROR_NOERROR) \
|
||||||
|
{ \
|
||||||
|
decodeWaitedOn = 0; \
|
||||||
|
if(openAudioDevice(&(cb->audioFormat))<0) { \
|
||||||
|
strncpy(pc->erroredFile,pc->file,MAXPATHLEN); \
|
||||||
|
pc->erroredFile[MAXPATHLEN] = '\0'; \
|
||||||
|
pc->error = PLAYER_ERROR_AUDIO; \
|
||||||
|
quitDecode(pc,dc); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
pc->totalTime = dc->totalTime; \
|
||||||
|
pc->sampleRate = dc->audioFormat.sampleRate; \
|
||||||
|
pc->bits = dc->audioFormat.bits; \
|
||||||
|
pc->channels = dc->audioFormat.channels; \
|
||||||
|
} \
|
||||||
|
else if(dc->state!=DECODE_STATE_START || *decode_pid <= 0) { \
|
||||||
strncpy(pc->erroredFile,pc->file,MAXPATHLEN); \
|
strncpy(pc->erroredFile,pc->file,MAXPATHLEN); \
|
||||||
pc->erroredFile[MAXPATHLEN] = '\0'; \
|
pc->erroredFile[MAXPATHLEN] = '\0'; \
|
||||||
pc->error = PLAYER_ERROR_AUDIO; \
|
pc->error = PLAYER_ERROR_FILE; \
|
||||||
quitDecode(pc,dc); \
|
quitDecode(pc,dc); \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
pc->totalTime = dc->totalTime; \
|
else { \
|
||||||
pc->sampleRate = dc->audioFormat.sampleRate; \
|
my_usleep(10000); \
|
||||||
pc->bits = dc->audioFormat.bits; \
|
continue; \
|
||||||
pc->channels = dc->audioFormat.channels; \
|
} \
|
||||||
} \
|
|
||||||
else if(decodeWaitedOn) { \
|
|
||||||
my_usleep(10000); \
|
|
||||||
continue; \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int waitOnDecode(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
|
int waitOnDecode(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
|
||||||
@ -226,7 +238,7 @@ int decodeSeek(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
|
|||||||
if(decodeSeek(pc,dc,cb,&decodeWaitedOn) == 0) { \
|
if(decodeSeek(pc,dc,cb,&decodeWaitedOn) == 0) { \
|
||||||
doCrossFade = 0; \
|
doCrossFade = 0; \
|
||||||
nextChunk = -1; \
|
nextChunk = -1; \
|
||||||
bbp = 0; \
|
bbp = 0; \
|
||||||
seeking = 1; \
|
seeking = 1; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@ -255,7 +267,7 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
dc->start = 0;
|
dc->start = 0;
|
||||||
|
|
||||||
while(!inputStreamAtEOF(&inStream) && bufferInputStream(&inStream) < 0
|
while(!inputStreamAtEOF(&inStream) && bufferInputStream(&inStream) < 0
|
||||||
&& !dc->stop);
|
&& !pc->stop);
|
||||||
|
|
||||||
if(dc->stop) {
|
if(dc->stop) {
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
@ -265,6 +277,14 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
|
|
||||||
switch(pc->decodeType) {
|
switch(pc->decodeType) {
|
||||||
case DECODE_TYPE_URL:
|
case DECODE_TYPE_URL:
|
||||||
|
#ifdef HAVE_OGG
|
||||||
|
if(pc->fileSuffix == DECODE_SUFFIX_OGG || (inStream.mime &&
|
||||||
|
0 == strcmp(inStream.mime, "application/ogg")))
|
||||||
|
{
|
||||||
|
ret = ogg_decode(cb, dc, &inStream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef HAVE_MAD
|
#ifdef HAVE_MAD
|
||||||
/*if(pc->fileSuffix == DECODE_SUFFIX_MP3 || (inStream.mime &&
|
/*if(pc->fileSuffix == DECODE_SUFFIX_MP3 || (inStream.mime &&
|
||||||
0 == strcmp(inStream.mime, "audio/mpeg")))*/
|
0 == strcmp(inStream.mime, "audio/mpeg")))*/
|
||||||
@ -281,6 +301,12 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_OGG
|
||||||
|
if(pc->fileSuffix == DECODE_SUFFIX_OGG) {
|
||||||
|
ret = ogg_decode(cb, dc, &inStream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef HAVE_FAAD
|
#ifdef HAVE_FAAD
|
||||||
if(pc->fileSuffix == DECODE_SUFFIX_AAC) {
|
if(pc->fileSuffix == DECODE_SUFFIX_AAC) {
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
@ -293,13 +319,6 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_OGG
|
|
||||||
if(pc->fileSuffix == DECODE_SUFFIX_OGG) {
|
|
||||||
closeInputStream(&inStream);
|
|
||||||
ret = ogg_decode(cb,dc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_FLAC
|
#ifdef HAVE_FLAC
|
||||||
if(pc->fileSuffix == DECODE_SUFFIX_FLAC) {
|
if(pc->fileSuffix == DECODE_SUFFIX_FLAC) {
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
@ -321,8 +340,10 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
strncpy(pc->erroredFile, dc->file, MAXPATHLEN);
|
strncpy(pc->erroredFile, dc->file, MAXPATHLEN);
|
||||||
pc->erroredFile[MAXPATHLEN] = '\0';
|
pc->erroredFile[MAXPATHLEN] = '\0';
|
||||||
if(ret != DECODE_ERROR_UNKTYPE) dc->error = DECODE_ERROR_FILE;
|
if(ret != DECODE_ERROR_UNKTYPE) dc->error = DECODE_ERROR_FILE;
|
||||||
else closeInputStream(&inStream);
|
else {
|
||||||
dc->start = 0;
|
dc->error = DECODE_ERROR_UNKTYPE;
|
||||||
|
closeInputStream(&inStream);
|
||||||
|
}
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
}
|
}
|
||||||
@ -341,16 +362,15 @@ int decoderInit(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
unblockSignals();
|
unblockSignals();
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if(dc->start) decodeStart(pc, cb, dc);
|
|
||||||
else if(dc->stop) {
|
|
||||||
dc->state = DECODE_STATE_STOP;
|
|
||||||
dc->stop = 0;
|
|
||||||
}
|
|
||||||
else if(dc->seek) dc->start = 1;
|
|
||||||
if(dc->cycleLogFiles) {
|
if(dc->cycleLogFiles) {
|
||||||
myfprintfCloseAndOpenLogFile();
|
myfprintfCloseAndOpenLogFile();
|
||||||
dc->cycleLogFiles = 0;
|
dc->cycleLogFiles = 0;
|
||||||
}
|
}
|
||||||
|
else if(dc->start) decodeStart(pc, cb, dc);
|
||||||
|
else if(dc->stop) {
|
||||||
|
dc->state = DECODE_STATE_STOP;
|
||||||
|
dc->stop = 0;
|
||||||
|
}
|
||||||
else my_usleep(10000);
|
else my_usleep(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,7 +412,7 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
|
|||||||
pc->play = 0;
|
pc->play = 0;
|
||||||
pc->beginTime = pc->elapsedTime;
|
pc->beginTime = pc->elapsedTime;
|
||||||
kill(getppid(),SIGUSR1);
|
kill(getppid(),SIGUSR1);
|
||||||
|
|
||||||
while(*decode_pid>0 && !cb->wrap && cb->end-cb->begin<bbp &&
|
while(*decode_pid>0 && !cb->wrap && cb->end-cb->begin<bbp &&
|
||||||
dc->state!=DECODE_STATE_STOP)
|
dc->state!=DECODE_STATE_STOP)
|
||||||
{
|
{
|
||||||
@ -578,8 +598,10 @@ void decode() {
|
|||||||
pc = &(getPlayerData()->playerControl);
|
pc = &(getPlayerData()->playerControl);
|
||||||
dc = &(getPlayerData()->decoderControl);
|
dc = &(getPlayerData()->decoderControl);
|
||||||
dc->error = 0;
|
dc->error = 0;
|
||||||
dc->start = 1;
|
|
||||||
cb->next = -1;
|
cb->next = -1;
|
||||||
|
dc->seek = 0;
|
||||||
|
dc->stop = 0;
|
||||||
|
dc->start = 1;
|
||||||
|
|
||||||
if(decode_pid==NULL || *decode_pid<=0) {
|
if(decode_pid==NULL || *decode_pid<=0) {
|
||||||
if(decoderInit(pc,cb,dc)<0) return;
|
if(decoderInit(pc,cb,dc)<0) return;
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
#define HTTP_BUFFER_SIZE 524289
|
#define HTTP_BUFFER_SIZE 524289
|
||||||
#define HTTP_PREBUFFER_SIZE (HTTP_BUFFER_SIZE >> 2)
|
#define HTTP_PREBUFFER_SIZE (HTTP_BUFFER_SIZE >> 2)
|
||||||
|
//#define HTTP_PREBUFFER_SIZE 0
|
||||||
|
|
||||||
#define HTTP_REDIRECT_MAX 10
|
#define HTTP_REDIRECT_MAX 10
|
||||||
|
|
||||||
|
@ -556,9 +556,12 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
|
|||||||
mp3DecodeData data;
|
mp3DecodeData data;
|
||||||
|
|
||||||
if(openMp3FromInputStream(inStream, &data, dc) < 0) {
|
if(openMp3FromInputStream(inStream, &data, dc) < 0) {
|
||||||
ERROR("Input does not appear to be a mp3 bit stream.\n");
|
|
||||||
closeInputStream(inStream);
|
closeInputStream(inStream);
|
||||||
return -1;
|
if(!dc->stop) {
|
||||||
|
ERROR("Input does not appear to be a mp3 bit stream.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
initAudioFormatFromMp3DecodeData(&data, &(dc->audioFormat));
|
initAudioFormatFromMp3DecodeData(&data, &(dc->audioFormat));
|
||||||
|
@ -42,6 +42,11 @@
|
|||||||
#define OGG_DECODE_USE_BIGENDIAN 0
|
#define OGG_DECODE_USE_BIGENDIAN 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct _OggCallbackData {
|
||||||
|
InputStream * inStream;
|
||||||
|
DecoderControl * dc;
|
||||||
|
} OggCallbackData;
|
||||||
|
|
||||||
/* this is just for tag parsing for db import! */
|
/* this is just for tag parsing for db import! */
|
||||||
int getOggTotalTime(char * file) {
|
int getOggTotalTime(char * file) {
|
||||||
OggVorbis_File vf;
|
OggVorbis_File vf;
|
||||||
@ -62,26 +67,42 @@ int getOggTotalTime(char * file) {
|
|||||||
return totalTime;
|
return totalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ogg_read_cb(void * ptr, size_t size, size_t nmemb, void * inStream)
|
size_t ogg_read_cb(void * ptr, size_t size, size_t nmemb, void * vdata)
|
||||||
{
|
{
|
||||||
size_t ret;
|
size_t ret = 0;
|
||||||
ret = readFromInputStream((InputStream *)inStream,ptr,size,nmemb);
|
OggCallbackData * data = (OggCallbackData *)vdata;
|
||||||
|
|
||||||
if(ret<0) errno = ((InputStream *)inStream)->error;
|
while(1) {
|
||||||
|
ret = readFromInputStream(data->inStream,ptr,size,nmemb);
|
||||||
|
if(ret == 0 && !inputStreamAtEOF(data->inStream) &&
|
||||||
|
!data->dc->stop)
|
||||||
|
{
|
||||||
|
my_usleep(10000);
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
errno = 0;
|
||||||
|
/*if(ret<0) errno = ((InputStream *)inStream)->error;*/
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ogg_seek_cb(void * inStream, ogg_int64_t offset, int whence) {
|
int ogg_seek_cb(void * vdata, ogg_int64_t offset, int whence) {
|
||||||
return seekInputStream((InputStream *)inStream,offset,whence);
|
OggCallbackData * data = (OggCallbackData *)vdata;
|
||||||
|
|
||||||
|
return seekInputStream(data->inStream,offset,whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ogg_close_cb(void * inStream) {
|
int ogg_close_cb(void * vdata) {
|
||||||
return closeInputStream((InputStream *)inStream);
|
OggCallbackData * data = (OggCallbackData *)vdata;
|
||||||
|
|
||||||
|
return closeInputStream(data->inStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
long ogg_tell_cb(void * inStream) {
|
long ogg_tell_cb(void * vdata) {
|
||||||
return ((InputStream *)inStream)->offset;
|
OggCallbackData * data = (OggCallbackData *)vdata;
|
||||||
|
|
||||||
|
return (long)(data->inStream->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
char * ogg_parseComment(char * comment, char * needle) {
|
char * ogg_parseComment(char * comment, char * needle) {
|
||||||
@ -142,27 +163,27 @@ float ogg_getReplayGainScale(char ** comments) {
|
|||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ogg_decode(OutputBuffer * cb, DecoderControl * dc)
|
int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
|
||||||
{
|
{
|
||||||
OggVorbis_File vf;
|
OggVorbis_File vf;
|
||||||
ov_callbacks callbacks;
|
ov_callbacks callbacks;
|
||||||
InputStream inStream;
|
OggCallbackData data;
|
||||||
|
|
||||||
|
data.inStream = inStream;
|
||||||
|
data.dc = dc;
|
||||||
|
|
||||||
callbacks.read_func = ogg_read_cb;
|
callbacks.read_func = ogg_read_cb;
|
||||||
callbacks.seek_func = ogg_seek_cb;
|
callbacks.seek_func = ogg_seek_cb;
|
||||||
callbacks.close_func = ogg_close_cb;
|
callbacks.close_func = ogg_close_cb;
|
||||||
callbacks.tell_func = ogg_tell_cb;
|
callbacks.tell_func = ogg_tell_cb;
|
||||||
|
|
||||||
if(openInputStream(&inStream,dc->file)<0) {
|
if(ov_open_callbacks(&data, &vf, NULL, 0, callbacks) < 0) {
|
||||||
ERROR("failed to open ogg\n");
|
closeInputStream(inStream);
|
||||||
return -1;
|
if(!dc->stop) {
|
||||||
}
|
ERROR("Input does not appear to be an Ogg Vorbis stream.\n");
|
||||||
|
return -1;
|
||||||
if(ov_open_callbacks(&inStream, &vf, NULL, 0, callbacks) < 0) {
|
}
|
||||||
ERROR("Input does not appear to be an Ogg bit stream.\n");
|
return 0;
|
||||||
closeInputStream(&inStream);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -190,20 +211,23 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc)
|
|||||||
|
|
||||||
while(!eof) {
|
while(!eof) {
|
||||||
if(dc->seek) {
|
if(dc->seek) {
|
||||||
clearOutputBuffer(cb);
|
if(0 == ov_time_seek_page(&vf,dc->seekWhere)) {
|
||||||
chunkpos = 0;
|
clearOutputBuffer(cb);
|
||||||
dc->seekChunk = cb->end;
|
chunkpos = 0;
|
||||||
ov_time_seek_page(&vf,dc->seekWhere);
|
dc->seekChunk = cb->end;
|
||||||
|
}
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
}
|
||||||
ret = ov_read(&vf, chunk+chunkpos,
|
ret = ov_read(&vf, chunk+chunkpos,
|
||||||
OGG_CHUNK_SIZE-chunkpos,
|
OGG_CHUNK_SIZE-chunkpos,
|
||||||
OGG_DECODE_USE_BIGENDIAN,
|
OGG_DECODE_USE_BIGENDIAN,
|
||||||
2, 1, ¤t_section);
|
2, 1, ¤t_section);
|
||||||
if(ret<=0) {
|
|
||||||
|
if(ret <= 0 && ret != OV_HOLE) {
|
||||||
eof = 1;
|
eof = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if(ret == OV_HOLE) ret = 0;
|
||||||
|
|
||||||
chunkpos+=ret;
|
chunkpos+=ret;
|
||||||
|
|
||||||
|
@ -22,10 +22,11 @@
|
|||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
|
|
||||||
#include "playerData.h"
|
#include "playerData.h"
|
||||||
|
#include "inputStream.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int ogg_decode(OutputBuffer * cb, DecoderControl * dc);
|
int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream);
|
||||||
|
|
||||||
int getOggTotalTime(char * file);
|
int getOggTotalTime(char * file);
|
||||||
|
|
||||||
|
@ -419,6 +419,7 @@ void playerQueueUnlock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int playerSeek(FILE * fp, Song * song, float time) {
|
int playerSeek(FILE * fp, Song * song, float time) {
|
||||||
|
printf("seek called\n");
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||||
char * file;
|
char * file;
|
||||||
int decodeType;
|
int decodeType;
|
||||||
|
Loading…
Reference in New Issue
Block a user