icynames are now copied to title of streams
git-svn-id: https://svn.musicpd.org/mpd/trunk@1258 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
parent
b4a91d574f
commit
000e053ce7
61
src/decode.c
61
src/decode.c
@ -103,8 +103,9 @@ int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) {
|
|||||||
{ \
|
{ \
|
||||||
decodeWaitedOn = 0; \
|
decodeWaitedOn = 0; \
|
||||||
if(openAudioDevice(&(cb->audioFormat))<0) { \
|
if(openAudioDevice(&(cb->audioFormat))<0) { \
|
||||||
strncpy(pc->erroredFile,pc->file,MAXPATHLEN); \
|
strncpy(pc->erroredUrl, pc->utf8url, \
|
||||||
pc->erroredFile[MAXPATHLEN] = '\0'; \
|
MAXPATHLEN); \
|
||||||
|
pc->erroredUrl[MAXPATHLEN] = '\0'; \
|
||||||
pc->error = PLAYER_ERROR_AUDIO; \
|
pc->error = PLAYER_ERROR_AUDIO; \
|
||||||
quitDecode(pc,dc); \
|
quitDecode(pc,dc); \
|
||||||
return; \
|
return; \
|
||||||
@ -115,8 +116,8 @@ int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) {
|
|||||||
pc->channels = dc->audioFormat.channels; \
|
pc->channels = dc->audioFormat.channels; \
|
||||||
} \
|
} \
|
||||||
else if(dc->state!=DECODE_STATE_START || *decode_pid <= 0) { \
|
else if(dc->state!=DECODE_STATE_START || *decode_pid <= 0) { \
|
||||||
strncpy(pc->erroredFile,pc->file,MAXPATHLEN); \
|
strncpy(pc->erroredUrl, pc->utf8url, MAXPATHLEN); \
|
||||||
pc->erroredFile[MAXPATHLEN] = '\0'; \
|
pc->erroredUrl[MAXPATHLEN] = '\0'; \
|
||||||
pc->error = PLAYER_ERROR_FILE; \
|
pc->error = PLAYER_ERROR_FILE; \
|
||||||
quitDecode(pc,dc); \
|
quitDecode(pc,dc); \
|
||||||
return; \
|
return; \
|
||||||
@ -133,8 +134,8 @@ int waitOnDecode(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
|
|||||||
while(decode_pid && *decode_pid>0 && dc->start) my_usleep(10000);
|
while(decode_pid && *decode_pid>0 && dc->start) my_usleep(10000);
|
||||||
|
|
||||||
if(dc->start || dc->error!=DECODE_ERROR_NOERROR) {
|
if(dc->start || dc->error!=DECODE_ERROR_NOERROR) {
|
||||||
strncpy(pc->erroredFile,pc->file,MAXPATHLEN);
|
strncpy(pc->erroredUrl, pc->utf8url, MAXPATHLEN);
|
||||||
pc->erroredFile[MAXPATHLEN] = '\0';
|
pc->erroredUrl[MAXPATHLEN] = '\0';
|
||||||
pc->error = PLAYER_ERROR_FILE;
|
pc->error = PLAYER_ERROR_FILE;
|
||||||
quitDecode(pc,dc);
|
quitDecode(pc,dc);
|
||||||
return -1;
|
return -1;
|
||||||
@ -159,7 +160,7 @@ int decodeSeek(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
|
|||||||
if(decode_pid && *decode_pid>0) {
|
if(decode_pid && *decode_pid>0) {
|
||||||
cb->next = -1;
|
cb->next = -1;
|
||||||
if(dc->state==DECODE_STATE_STOP || dc->error ||
|
if(dc->state==DECODE_STATE_STOP || dc->error ||
|
||||||
strcmp(dc->file,pc->file)!=0)
|
strcmp(dc->utf8url, pc->utf8url)!=0)
|
||||||
{
|
{
|
||||||
stopDecode(dc);
|
stopDecode(dc);
|
||||||
cb->begin = 0;
|
cb->begin = 0;
|
||||||
@ -209,8 +210,9 @@ int decodeSeek(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
|
|||||||
if(pause) pc->state = PLAYER_STATE_PAUSE; \
|
if(pause) pc->state = PLAYER_STATE_PAUSE; \
|
||||||
else { \
|
else { \
|
||||||
if(openAudioDevice(NULL)<0) { \
|
if(openAudioDevice(NULL)<0) { \
|
||||||
strncpy(pc->erroredFile,pc->file,MAXPATHLEN); \
|
strncpy(pc->erroredUrl, pc->utf8url, \
|
||||||
pc->erroredFile[MAXPATHLEN] = '\0'; \
|
MAXPATHLEN); \
|
||||||
|
pc->erroredUrl[MAXPATHLEN] = '\0'; \
|
||||||
pc->error = PLAYER_ERROR_AUDIO; \
|
pc->error = PLAYER_ERROR_AUDIO; \
|
||||||
quitDecode(pc,dc); \
|
quitDecode(pc,dc); \
|
||||||
return; \
|
return; \
|
||||||
@ -239,11 +241,22 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
int ret;
|
int ret;
|
||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
InputPlugin * plugin;
|
InputPlugin * plugin;
|
||||||
|
char path[MAXPATHLEN+1];
|
||||||
|
|
||||||
strncpy(dc->file,pc->file,MAXPATHLEN);
|
if(isRemoteUrl(pc->utf8url)) {
|
||||||
dc->file[MAXPATHLEN] = '\0';
|
strncpy(path, pc->utf8url, MAXPATHLEN);
|
||||||
|
}
|
||||||
|
else strncpy(path, rmp2amp(utf8ToFsCharset(pc->utf8url)), MAXPATHLEN);
|
||||||
|
path[MAXPATHLEN] = '\0';
|
||||||
|
|
||||||
if(openInputStream(&inStream,dc->file) < 0) {
|
dc->metadataSet = 0;
|
||||||
|
memset(dc->metadata, 0, DECODE_METADATA_LENGTH);
|
||||||
|
dc->title = -1;
|
||||||
|
|
||||||
|
strncpy(dc->utf8url, pc->utf8url, MAXPATHLEN);
|
||||||
|
dc->utf8url[MAXPATHLEN] = '\0';
|
||||||
|
|
||||||
|
if(openInputStream(&inStream, path) < 0) {
|
||||||
dc->error = DECODE_ERROR_FILE;
|
dc->error = DECODE_ERROR_FILE;
|
||||||
dc->start = 0;
|
dc->start = 0;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
@ -264,11 +277,19 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(inStream.metaTitle) {
|
||||||
|
strncpy(dc->metadata, inStream.metaTitle,
|
||||||
|
DECODE_METADATA_LENGTH-1);
|
||||||
|
dc->title = 0;
|
||||||
|
dc->metadataSet = 1;
|
||||||
|
}
|
||||||
|
|
||||||
ret = DECODE_ERROR_UNKTYPE;
|
ret = DECODE_ERROR_UNKTYPE;
|
||||||
if(isRemoteUrl(pc->file)) {
|
if(isRemoteUrl(pc->utf8url)) {
|
||||||
plugin = getInputPluginFromMimeType(inStream.mime);
|
plugin = getInputPluginFromMimeType(inStream.mime);
|
||||||
if(plugin == NULL) {
|
if(plugin == NULL) {
|
||||||
plugin = getInputPluginFromSuffix(getSuffix(dc->file));
|
plugin = getInputPluginFromSuffix(
|
||||||
|
getSuffix(dc->utf8url));
|
||||||
}
|
}
|
||||||
if(plugin && (plugin->streamTypes & INPUT_PLUGIN_STREAM_URL) &&
|
if(plugin && (plugin->streamTypes & INPUT_PLUGIN_STREAM_URL) &&
|
||||||
plugin->streamDecodeFunc)
|
plugin->streamDecodeFunc)
|
||||||
@ -277,7 +298,7 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
plugin = getInputPluginFromSuffix(getSuffix(dc->file));
|
plugin = getInputPluginFromSuffix(getSuffix(dc->utf8url));
|
||||||
if(plugin && (plugin->streamTypes && INPUT_PLUGIN_STREAM_FILE))
|
if(plugin && (plugin->streamTypes && INPUT_PLUGIN_STREAM_FILE))
|
||||||
{
|
{
|
||||||
if(plugin->streamDecodeFunc) {
|
if(plugin->streamDecodeFunc) {
|
||||||
@ -286,14 +307,14 @@ void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
}
|
}
|
||||||
else if(plugin->fileDecodeFunc) {
|
else if(plugin->fileDecodeFunc) {
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
ret = plugin->fileDecodeFunc(cb, dc);
|
ret = plugin->fileDecodeFunc(cb, dc, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ret<0 || ret == DECODE_ERROR_UNKTYPE) {
|
if(ret<0 || ret == DECODE_ERROR_UNKTYPE) {
|
||||||
strncpy(pc->erroredFile, dc->file, MAXPATHLEN);
|
strncpy(pc->erroredUrl, dc->utf8url, MAXPATHLEN);
|
||||||
pc->erroredFile[MAXPATHLEN] = '\0';
|
pc->erroredUrl[MAXPATHLEN] = '\0';
|
||||||
if(ret != DECODE_ERROR_UNKTYPE) dc->error = DECODE_ERROR_FILE;
|
if(ret != DECODE_ERROR_UNKTYPE) dc->error = DECODE_ERROR_FILE;
|
||||||
else {
|
else {
|
||||||
dc->error = DECODE_ERROR_UNKTYPE;
|
dc->error = DECODE_ERROR_UNKTYPE;
|
||||||
@ -334,8 +355,8 @@ int decoderInit(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
}
|
}
|
||||||
else if(pid<0) {
|
else if(pid<0) {
|
||||||
unblockSignals();
|
unblockSignals();
|
||||||
strncpy(pc->erroredFile,pc->file,MAXPATHLEN);
|
strncpy(pc->erroredUrl, pc->utf8url, MAXPATHLEN);
|
||||||
pc->erroredFile[MAXPATHLEN] = '\0';
|
pc->erroredUrl[MAXPATHLEN] = '\0';
|
||||||
pc->error = PLAYER_ERROR_SYSTEM;
|
pc->error = PLAYER_ERROR_SYSTEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,8 @@
|
|||||||
#define DECODE_SUFFIX_MP4 5
|
#define DECODE_SUFFIX_MP4 5
|
||||||
#define DECODE_SUFFIX_WAVE 6
|
#define DECODE_SUFFIX_WAVE 6
|
||||||
|
|
||||||
|
#define DECODE_METADATA_LENGTH 4096
|
||||||
|
|
||||||
typedef struct _DecoderControl {
|
typedef struct _DecoderControl {
|
||||||
volatile mpd_sint8 state;
|
volatile mpd_sint8 state;
|
||||||
volatile mpd_sint8 stop;
|
volatile mpd_sint8 stop;
|
||||||
@ -55,9 +57,12 @@ typedef struct _DecoderControl {
|
|||||||
volatile mpd_sint8 seekable;
|
volatile mpd_sint8 seekable;
|
||||||
volatile mpd_sint8 cycleLogFiles;
|
volatile mpd_sint8 cycleLogFiles;
|
||||||
volatile double seekWhere;
|
volatile double seekWhere;
|
||||||
char file[MAXPATHLEN+1];
|
|
||||||
AudioFormat audioFormat;
|
AudioFormat audioFormat;
|
||||||
|
char utf8url[MAXPATHLEN+1];
|
||||||
volatile float totalTime;
|
volatile float totalTime;
|
||||||
|
volatile mpd_sint8 metadataSet;
|
||||||
|
char metadata[DECODE_METADATA_LENGTH];
|
||||||
|
volatile mpd_sint16 title;
|
||||||
} DecoderControl;
|
} DecoderControl;
|
||||||
|
|
||||||
void decodeSigHandler(int sig);
|
void decodeSigHandler(int sig);
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
typedef int (* InputPlugin_streamDecodeFunc) (OutputBuffer *, DecoderControl *,
|
typedef int (* InputPlugin_streamDecodeFunc) (OutputBuffer *, DecoderControl *,
|
||||||
InputStream *);
|
InputStream *);
|
||||||
|
|
||||||
typedef int (* InputPlugin_fileDecodeFunc) (OutputBuffer *, DecoderControl *);
|
typedef int (* InputPlugin_fileDecodeFunc) (OutputBuffer *, DecoderControl *,
|
||||||
|
char * path);
|
||||||
|
|
||||||
/* file should be the full path! */
|
/* file should be the full path! */
|
||||||
typedef MpdTag * (* InputPlugin_tagDupFunc) (char * file);
|
typedef MpdTag * (* InputPlugin_tagDupFunc) (char * file);
|
||||||
|
@ -250,7 +250,7 @@ int getAacTotalTime(char * file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int aac_decode(OutputBuffer * cb, DecoderControl * dc) {
|
int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
||||||
float time;
|
float time;
|
||||||
float totalTime;
|
float totalTime;
|
||||||
faacDecHandle decoder;
|
faacDecHandle decoder;
|
||||||
@ -270,9 +270,9 @@ int aac_decode(OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
AacBuffer b;
|
AacBuffer b;
|
||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
|
|
||||||
if((totalTime = getAacFloatTotalTime(dc->file)) < 0) return -1;
|
if((totalTime = getAacFloatTotalTime(path)) < 0) return -1;
|
||||||
|
|
||||||
if(openInputStream(&inStream,dc->file) < 0) return -1;
|
if(openInputStream(&inStream, path) < 0) return -1;
|
||||||
|
|
||||||
initAacBuffer(&inStream,&b,NULL,NULL,NULL);
|
initAacBuffer(&inStream,&b,NULL,NULL,NULL);
|
||||||
|
|
||||||
@ -328,7 +328,7 @@ int aac_decode(OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(frameInfo.error > 0) {
|
if(frameInfo.error > 0) {
|
||||||
ERROR("error decoding AAC file: %s\n",dc->file);
|
ERROR("error decoding AAC file: %s\n", path);
|
||||||
ERROR("faad2 error: %s\n",
|
ERROR("faad2 error: %s\n",
|
||||||
faacDecGetErrorMessage(frameInfo.error));
|
faacDecGetErrorMessage(frameInfo.error));
|
||||||
eof = 1;
|
eof = 1;
|
||||||
|
@ -51,21 +51,21 @@ int getAudiofileTotalTime(char * file)
|
|||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
int audiofile_decode(OutputBuffer * cb, DecoderControl * dc) {
|
int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
||||||
int fs, frame_count;
|
int fs, frame_count;
|
||||||
AFfilehandle af_fp;
|
AFfilehandle af_fp;
|
||||||
int bits;
|
int bits;
|
||||||
mpd_uint16 bitRate;
|
mpd_uint16 bitRate;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if(stat(dc->file,&st) < 0) {
|
if(stat(path, &st) < 0) {
|
||||||
ERROR("failed to stat: %s\n",dc->file);
|
ERROR("failed to stat: %s\n", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
af_fp = afOpenFile(dc->file,"r", NULL);
|
af_fp = afOpenFile(path, "r", NULL);
|
||||||
if(af_fp == AF_NULL_FILEHANDLE) {
|
if(af_fp == AF_NULL_FILEHANDLE) {
|
||||||
ERROR("failed to open: %s\n",dc->file);
|
ERROR("failed to open: %s\n", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ int audiofile_decode(OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
|
|
||||||
if (dc->audioFormat.bits != 8 && dc->audioFormat.bits != 16) {
|
if (dc->audioFormat.bits != 8 && dc->audioFormat.bits != 16) {
|
||||||
ERROR("Only 8 and 16-bit files are supported. %s is %i-bit\n",
|
ERROR("Only 8 and 16-bit files are supported. %s is %i-bit\n",
|
||||||
dc->file,dc->audioFormat.bits);
|
path, dc->audioFormat.bits);
|
||||||
afCloseFile(af_fp);
|
afCloseFile(af_fp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ typedef struct {
|
|||||||
DecoderControl * dc;
|
DecoderControl * dc;
|
||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
float replayGainScale;
|
float replayGainScale;
|
||||||
|
char * path;
|
||||||
} FlacData;
|
} FlacData;
|
||||||
|
|
||||||
/* this code is based on flac123, from flac-tools */
|
/* this code is based on flac123, from flac-tools */
|
||||||
@ -68,7 +69,7 @@ FLAC__SeekableStreamDecoderLengthStatus flacLength(
|
|||||||
const FLAC__SeekableStreamDecoder *, FLAC__uint64 *, void *);
|
const FLAC__SeekableStreamDecoder *, FLAC__uint64 *, void *);
|
||||||
FLAC__bool flacEOF(const FLAC__SeekableStreamDecoder *, void *);
|
FLAC__bool flacEOF(const FLAC__SeekableStreamDecoder *, void *);
|
||||||
|
|
||||||
int flac_decode(OutputBuffer * cb, DecoderControl *dc) {
|
int flac_decode(OutputBuffer * cb, DecoderControl *dc, char * path) {
|
||||||
FLAC__SeekableStreamDecoder * flacDec;
|
FLAC__SeekableStreamDecoder * flacDec;
|
||||||
FlacData data;
|
FlacData data;
|
||||||
int status = 1;
|
int status = 1;
|
||||||
@ -80,9 +81,10 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc) {
|
|||||||
data.cb = cb;
|
data.cb = cb;
|
||||||
data.dc = dc;
|
data.dc = dc;
|
||||||
data.replayGainScale = 1.0;
|
data.replayGainScale = 1.0;
|
||||||
|
data.path = path;
|
||||||
|
|
||||||
if(openInputStream(&(data.inStream),dc->file)<0) {
|
if(openInputStream(&(data.inStream), path)<0) {
|
||||||
ERROR("unable to open flac: %s\n",dc->file);
|
ERROR("unable to open flac: %s\n", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,10 +108,10 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc) {
|
|||||||
status&=FLAC__seekable_stream_decoder_set_client_data(flacDec,
|
status&=FLAC__seekable_stream_decoder_set_client_data(flacDec,
|
||||||
(void *)&data);
|
(void *)&data);
|
||||||
if(!status) {
|
if(!status) {
|
||||||
ERROR("flac problem before init(): %s\n",dc->file);
|
ERROR("flac problem before init(): %s\n", path);
|
||||||
flacPrintErroredState(
|
flacPrintErroredState(
|
||||||
FLAC__seekable_stream_decoder_get_state(flacDec),
|
FLAC__seekable_stream_decoder_get_state(flacDec),
|
||||||
dc->file);
|
path);
|
||||||
FLAC__seekable_stream_decoder_delete(flacDec);
|
FLAC__seekable_stream_decoder_delete(flacDec);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -117,19 +119,19 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc) {
|
|||||||
if(FLAC__seekable_stream_decoder_init(flacDec)!=
|
if(FLAC__seekable_stream_decoder_init(flacDec)!=
|
||||||
FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
|
FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
|
||||||
{
|
{
|
||||||
ERROR("flac problem doing init(): %s\n",dc->file);
|
ERROR("flac problem doing init(): %s\n", path);
|
||||||
flacPrintErroredState(
|
flacPrintErroredState(
|
||||||
FLAC__seekable_stream_decoder_get_state(flacDec),
|
FLAC__seekable_stream_decoder_get_state(flacDec),
|
||||||
dc->file);
|
path);
|
||||||
FLAC__seekable_stream_decoder_delete(flacDec);
|
FLAC__seekable_stream_decoder_delete(flacDec);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDec)) {
|
if(!FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDec)) {
|
||||||
ERROR("flac problem reading metadata: %s\n", dc->file);
|
ERROR("flac problem reading metadata: %s\n", path);
|
||||||
flacPrintErroredState(
|
flacPrintErroredState(
|
||||||
FLAC__seekable_stream_decoder_get_state(flacDec),
|
FLAC__seekable_stream_decoder_get_state(flacDec),
|
||||||
dc->file);
|
path);
|
||||||
FLAC__seekable_stream_decoder_delete(flacDec);
|
FLAC__seekable_stream_decoder_delete(flacDec);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -163,7 +165,7 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc) {
|
|||||||
if(!dc->stop) {
|
if(!dc->stop) {
|
||||||
flacPrintErroredState(
|
flacPrintErroredState(
|
||||||
FLAC__seekable_stream_decoder_get_state(flacDec),
|
FLAC__seekable_stream_decoder_get_state(flacDec),
|
||||||
dc->file);
|
path);
|
||||||
FLAC__seekable_stream_decoder_finish(flacDec);
|
FLAC__seekable_stream_decoder_finish(flacDec);
|
||||||
}
|
}
|
||||||
FLAC__seekable_stream_decoder_delete(flacDec);
|
FLAC__seekable_stream_decoder_delete(flacDec);
|
||||||
@ -253,16 +255,16 @@ void flacError(const FLAC__SeekableStreamDecoder *dec,
|
|||||||
|
|
||||||
switch(status) {
|
switch(status) {
|
||||||
case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
|
case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
|
||||||
ERROR("flac lost sync: %s\n",data->dc->file);
|
ERROR("flac lost sync: %s\n", data->path);
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
|
case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
|
||||||
ERROR("bad header %s\n",data->dc->file);
|
ERROR("bad header %s\n", data->path);
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
|
case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
|
||||||
ERROR("crc mismatch %s\n",data->dc->file);
|
ERROR("crc mismatch %s\n", data->path);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ERROR("unknow flac error %s\n",data->dc->file);
|
ERROR("unknow flac error %s\n", data->path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ uint32_t mp4_inputStreamSeekCallback(void *inStream, uint64_t position) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int mp4_decode(OutputBuffer * cb, DecoderControl * dc) {
|
int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
||||||
mp4ff_t * mp4fh;
|
mp4ff_t * mp4fh;
|
||||||
mp4ff_callback_t * mp4cb;
|
mp4ff_callback_t * mp4cb;
|
||||||
int32_t track;
|
int32_t track;
|
||||||
@ -113,8 +113,8 @@ int mp4_decode(OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
mpd_uint16 bitRate = 0;
|
mpd_uint16 bitRate = 0;
|
||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
|
|
||||||
if(openInputStream(&inStream,dc->file) < 0) {
|
if(openInputStream(&inStream, path) < 0) {
|
||||||
ERROR("failed to open %s\n",dc->file);
|
ERROR("failed to open %s\n", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +241,7 @@ int mp4_decode(OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
|
|
||||||
if(mp4Buffer) free(mp4Buffer);
|
if(mp4Buffer) free(mp4Buffer);
|
||||||
if(frameInfo.error > 0) {
|
if(frameInfo.error > 0) {
|
||||||
ERROR("error decoding MP4 file: %s\n",dc->file);
|
ERROR("error decoding MP4 file: %s\n", path);
|
||||||
ERROR("faad2 error: %s\n",
|
ERROR("faad2 error: %s\n",
|
||||||
faacDecGetErrorMessage(frameInfo.error));
|
faacDecGetErrorMessage(frameInfo.error));
|
||||||
eof = 1;
|
eof = 1;
|
||||||
|
@ -45,6 +45,7 @@ struct _InputStream {
|
|||||||
InputStreamAtEOFFunc atEOFFunc;
|
InputStreamAtEOFFunc atEOFFunc;
|
||||||
InputStreamBufferFunc bufferFunc;
|
InputStreamBufferFunc bufferFunc;
|
||||||
void * data;
|
void * data;
|
||||||
|
char * metaTitle;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* if an error occurs for these 3 functions, then -1 is returned and errno
|
/* if an error occurs for these 3 functions, then -1 is returned and errno
|
||||||
|
@ -35,6 +35,7 @@ int inputStream_fileOpen(InputStream * inStream, char * filename) {
|
|||||||
inStream->offset = 0;
|
inStream->offset = 0;
|
||||||
inStream->seekable = 1;
|
inStream->seekable = 1;
|
||||||
inStream->mime = NULL;
|
inStream->mime = NULL;
|
||||||
|
inStream->metaTitle = NULL;
|
||||||
|
|
||||||
fseek(fp,0,SEEK_END);
|
fseek(fp,0,SEEK_END);
|
||||||
inStream->size = ftell(fp);
|
inStream->size = ftell(fp);
|
||||||
|
@ -56,7 +56,6 @@ typedef struct _InputStreemHTTPData {
|
|||||||
size_t buflen;
|
size_t buflen;
|
||||||
int timesRedirected;
|
int timesRedirected;
|
||||||
int icyMetaint;
|
int icyMetaint;
|
||||||
char * icyName;
|
|
||||||
int prebuffer;
|
int prebuffer;
|
||||||
} InputStreamHTTPData;
|
} InputStreamHTTPData;
|
||||||
|
|
||||||
@ -68,7 +67,6 @@ static InputStreamHTTPData * newInputStreamHTTPData() {
|
|||||||
ret->port = 80;
|
ret->port = 80;
|
||||||
ret->connState = HTTP_CONN_STATE_CLOSED;
|
ret->connState = HTTP_CONN_STATE_CLOSED;
|
||||||
ret->timesRedirected = 0;
|
ret->timesRedirected = 0;
|
||||||
ret->icyName = NULL;
|
|
||||||
ret->icyMetaint = 0;
|
ret->icyMetaint = 0;
|
||||||
ret->prebuffer = 0;
|
ret->prebuffer = 0;
|
||||||
|
|
||||||
@ -78,7 +76,6 @@ static InputStreamHTTPData * newInputStreamHTTPData() {
|
|||||||
static void freeInputStreamHTTPData(InputStreamHTTPData * data) {
|
static void freeInputStreamHTTPData(InputStreamHTTPData * data) {
|
||||||
if(data->host) free(data->host);
|
if(data->host) free(data->host);
|
||||||
if(data->path) free(data->path);
|
if(data->path) free(data->path);
|
||||||
if(data->icyName) free(data->icyName);
|
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
@ -374,19 +371,20 @@ static int getHTTPHello(InputStream * inStream) {
|
|||||||
char * temp = strstr(cur+11,"\r\n");
|
char * temp = strstr(cur+11,"\r\n");
|
||||||
if(!temp) break;
|
if(!temp) break;
|
||||||
*temp = '\0';
|
*temp = '\0';
|
||||||
if(data->icyName) free(data->icyName);
|
if(inStream->metaTitle) free(inStream->metaTitle);
|
||||||
data->icyName = strdup(cur+11);
|
inStream->metaTitle = strdup(cur+19);
|
||||||
*temp = '\r';
|
*temp = '\r';
|
||||||
DEBUG("stream icy-name: %s\n", data->icyName);
|
DEBUG("stream icy-name: %s\n", inStream->metaTitle);
|
||||||
}
|
}
|
||||||
else if(0 == strncmp(cur, "\r\nx-audiocast-name:", 19)) {
|
else if(0 == strncmp(cur, "\r\nx-audiocast-name:", 19)) {
|
||||||
char * temp = strstr(cur+19,"\r\n");
|
char * temp = strstr(cur+19,"\r\n");
|
||||||
if(!temp) break;
|
if(!temp) break;
|
||||||
*temp = '\0';
|
*temp = '\0';
|
||||||
if(data->icyName) free(data->icyName);
|
if(inStream->metaTitle) free(inStream->metaTitle);
|
||||||
data->icyName = strdup(cur+19);
|
inStream->metaTitle = strdup(cur+19);
|
||||||
*temp = '\r';
|
*temp = '\r';
|
||||||
DEBUG("stream audiocast-name: %s\n", data->icyName);
|
DEBUG("stream audiocast-name: %s\n",
|
||||||
|
inStream->metaTitle);
|
||||||
}
|
}
|
||||||
else if(0 == strncmp(cur, "\r\nContent-Type:", 15)) {
|
else if(0 == strncmp(cur, "\r\nContent-Type:", 15)) {
|
||||||
int incr = 15;
|
int incr = 15;
|
||||||
@ -445,6 +443,7 @@ int inputStream_httpOpen(InputStream * inStream, char * url) {
|
|||||||
inStream->error = 0;
|
inStream->error = 0;
|
||||||
inStream->mime = NULL;
|
inStream->mime = NULL;
|
||||||
inStream->seekable = 0;
|
inStream->seekable = 0;
|
||||||
|
inStream->metaTitle = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
55
src/player.c
55
src/player.c
@ -23,7 +23,6 @@
|
|||||||
#include "playlist.h"
|
#include "playlist.h"
|
||||||
#include "ls.h"
|
#include "ls.h"
|
||||||
#include "listen.h"
|
#include "listen.h"
|
||||||
#include "path.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "tables.h"
|
#include "tables.h"
|
||||||
@ -179,12 +178,8 @@ int playerPlay(FILE * fp, Song * song) {
|
|||||||
if(song->tag) pc->fileTime = song->tag->time;
|
if(song->tag) pc->fileTime = song->tag->time;
|
||||||
else pc->fileTime = 0;
|
else pc->fileTime = 0;
|
||||||
|
|
||||||
if(isRemoteUrl(song->utf8url)) {
|
strncpy(pc->utf8url, song->utf8url, MAXPATHLEN);
|
||||||
strncpy(pc->file, song->utf8url, MAXPATHLEN);
|
pc->utf8url[MAXPATHLEN] = '\0';
|
||||||
}
|
|
||||||
else strncpy(pc->file, rmp2amp(utf8ToFsCharset(song->utf8url)),
|
|
||||||
MAXPATHLEN);
|
|
||||||
pc->file[MAXPATHLEN] = '\0';
|
|
||||||
|
|
||||||
pc->play = 1;
|
pc->play = 1;
|
||||||
if(player_pid==0 && playerInit()<0) {
|
if(player_pid==0 && playerInit()<0) {
|
||||||
@ -287,11 +282,11 @@ char * getPlayerErrorStr() {
|
|||||||
case PLAYER_ERROR_FILENOTFOUND:
|
case PLAYER_ERROR_FILENOTFOUND:
|
||||||
snprintf(error,errorlen,
|
snprintf(error,errorlen,
|
||||||
"file \"%s\" does not exist or is inaccesible",
|
"file \"%s\" does not exist or is inaccesible",
|
||||||
pc->erroredFile);
|
pc->erroredUrl);
|
||||||
break;
|
break;
|
||||||
case PLAYER_ERROR_FILE:
|
case PLAYER_ERROR_FILE:
|
||||||
snprintf(error,errorlen,"problems decoding \"%s\"",
|
snprintf(error,errorlen,"problems decoding \"%s\"",
|
||||||
pc->erroredFile);
|
pc->erroredUrl);
|
||||||
break;
|
break;
|
||||||
case PLAYER_ERROR_AUDIO:
|
case PLAYER_ERROR_AUDIO:
|
||||||
snprintf(error,errorlen,"problems opening audio device");
|
snprintf(error,errorlen,"problems opening audio device");
|
||||||
@ -301,7 +296,7 @@ char * getPlayerErrorStr() {
|
|||||||
break;
|
break;
|
||||||
case PLAYER_ERROR_UNKTYPE:
|
case PLAYER_ERROR_UNKTYPE:
|
||||||
snprintf(error,errorlen,"file type of \"%s\" is unknown",
|
snprintf(error,errorlen,"file type of \"%s\" is unknown",
|
||||||
pc->erroredFile);
|
pc->erroredUrl);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -327,12 +322,8 @@ int queueSong(Song * song) {
|
|||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(pc->queueState==PLAYER_QUEUE_BLANK) {
|
if(pc->queueState==PLAYER_QUEUE_BLANK) {
|
||||||
if(isRemoteUrl(song->utf8url)) {
|
strncpy(pc->utf8url, song->utf8url, MAXPATHLEN);
|
||||||
strncpy(pc->file, song->utf8url, MAXPATHLEN);
|
pc->utf8url[MAXPATHLEN] = '\0';
|
||||||
}
|
|
||||||
else strncpy(pc->file, rmp2amp(utf8ToFsCharset(song->utf8url)),
|
|
||||||
MAXPATHLEN);
|
|
||||||
pc->file[MAXPATHLEN] = '\0';
|
|
||||||
|
|
||||||
if(song->tag) pc->fileTime = song->tag->time;
|
if(song->tag) pc->fileTime = song->tag->time;
|
||||||
else pc->fileTime = 0;
|
else pc->fileTime = 0;
|
||||||
@ -378,7 +369,6 @@ void playerQueueUnlock() {
|
|||||||
|
|
||||||
int playerSeek(FILE * fp, Song * song, float time) {
|
int playerSeek(FILE * fp, Song * song, float time) {
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||||
char * file;
|
|
||||||
|
|
||||||
if(pc->state==PLAYER_STATE_STOP) {
|
if(pc->state==PLAYER_STATE_STOP) {
|
||||||
myfprintf(fp,"%s player not currently playing\n",
|
myfprintf(fp,"%s player not currently playing\n",
|
||||||
@ -386,14 +376,12 @@ int playerSeek(FILE * fp, Song * song, float time) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isRemoteUrl(song->utf8url)) file = song->utf8url;
|
if(strcmp(pc->utf8url, song->utf8url)!=0) {
|
||||||
else file = rmp2amp(utf8ToFsCharset(song->utf8url));
|
|
||||||
if(strcmp(pc->file,file)!=0) {
|
|
||||||
if(song->tag) pc->fileTime = song->tag->time;
|
if(song->tag) pc->fileTime = song->tag->time;
|
||||||
else pc->fileTime = 0;
|
else pc->fileTime = 0;
|
||||||
|
|
||||||
strncpy(pc->file,file,MAXPATHLEN);
|
strncpy(pc->utf8url, song->utf8url, MAXPATHLEN);
|
||||||
pc->file[MAXPATHLEN] = '\0';
|
pc->utf8url[MAXPATHLEN] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pc->error==PLAYER_ERROR_NOERROR) {
|
if(pc->error==PLAYER_ERROR_NOERROR) {
|
||||||
@ -471,4 +459,27 @@ void playerCycleLogFiles() {
|
|||||||
dc->cycleLogFiles = 1;
|
dc->cycleLogFiles = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* this actually creates a dupe of the current metadata */
|
||||||
|
Song * playerCurrentDecodeSong() {
|
||||||
|
static Song * song;
|
||||||
|
DecoderControl * dc = &(getPlayerData()->decoderControl);
|
||||||
|
|
||||||
|
if(dc->metadataSet && (!song || strcmp(song->utf8url, dc->utf8url))) {
|
||||||
|
if(!song) {
|
||||||
|
song = newNullSong();
|
||||||
|
song->tag = newMpdTag();
|
||||||
|
}
|
||||||
|
if(song->utf8url) free(song->utf8url);
|
||||||
|
song->utf8url = strdup(dc->utf8url);
|
||||||
|
if(dc->title >= 0) {
|
||||||
|
song->tag->title = dc->title + dc->metadata;
|
||||||
|
}
|
||||||
|
else song->tag->title = NULL;
|
||||||
|
|
||||||
|
return song;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
|
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
|
||||||
|
@ -66,8 +66,8 @@ typedef struct _PlayerControl {
|
|||||||
volatile float totalTime;
|
volatile float totalTime;
|
||||||
volatile float elapsedTime;
|
volatile float elapsedTime;
|
||||||
volatile float fileTime;
|
volatile float fileTime;
|
||||||
char file[MAXPATHLEN+1];
|
char utf8url[MAXPATHLEN+1];
|
||||||
char erroredFile[MAXPATHLEN+1];
|
char erroredUrl[MAXPATHLEN+1];
|
||||||
volatile mpd_sint8 queueState;
|
volatile mpd_sint8 queueState;
|
||||||
volatile mpd_sint8 queueLockState;
|
volatile mpd_sint8 queueLockState;
|
||||||
volatile mpd_sint8 lockQueue;
|
volatile mpd_sint8 lockQueue;
|
||||||
@ -145,5 +145,7 @@ int getPlayerChannels();
|
|||||||
|
|
||||||
void playerCycleLogFiles();
|
void playerCycleLogFiles();
|
||||||
|
|
||||||
|
Song * playerCurrentDecodeSong();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
|
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
|
||||||
|
@ -108,8 +108,8 @@ void initPlayerData() {
|
|||||||
playerData_pd->playerControl.queueState = PLAYER_QUEUE_BLANK;
|
playerData_pd->playerControl.queueState = PLAYER_QUEUE_BLANK;
|
||||||
playerData_pd->playerControl.queueLockState = PLAYER_QUEUE_UNLOCKED;
|
playerData_pd->playerControl.queueLockState = PLAYER_QUEUE_UNLOCKED;
|
||||||
playerData_pd->playerControl.seek = 0;
|
playerData_pd->playerControl.seek = 0;
|
||||||
memset(playerData_pd->playerControl.file,0,MAXPATHLEN+1);
|
memset(playerData_pd->playerControl.utf8url, 0, MAXPATHLEN+1);
|
||||||
memset(playerData_pd->playerControl.erroredFile,0,MAXPATHLEN+1);
|
memset(playerData_pd->playerControl.erroredUrl, 0, MAXPATHLEN+1);
|
||||||
playerData_pd->playerControl.crossFade = crossfade;
|
playerData_pd->playerControl.crossFade = crossfade;
|
||||||
playerData_pd->playerControl.softwareVolume = 1000;
|
playerData_pd->playerControl.softwareVolume = 1000;
|
||||||
playerData_pd->playerControl.totalPlayTime = 0;
|
playerData_pd->playerControl.totalPlayTime = 0;
|
||||||
@ -120,7 +120,11 @@ void initPlayerData() {
|
|||||||
playerData_pd->decoderControl.state = DECODE_STATE_STOP;
|
playerData_pd->decoderControl.state = DECODE_STATE_STOP;
|
||||||
playerData_pd->decoderControl.seek = 0;
|
playerData_pd->decoderControl.seek = 0;
|
||||||
playerData_pd->decoderControl.error = DECODE_ERROR_NOERROR;
|
playerData_pd->decoderControl.error = DECODE_ERROR_NOERROR;
|
||||||
memset(playerData_pd->decoderControl.file,0,MAXPATHLEN+1);
|
memset(playerData_pd->decoderControl.utf8url, 0, MAXPATHLEN+1);
|
||||||
|
memset(playerData_pd->decoderControl.metadata, 0,
|
||||||
|
DECODE_METADATA_LENGTH);
|
||||||
|
playerData_pd->decoderControl.title = -1;
|
||||||
|
playerData_pd->decoderControl.metadataSet = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerData * getPlayerData() {
|
PlayerData * getPlayerData() {
|
||||||
|
@ -734,11 +734,34 @@ int playPlaylist(FILE * fp, int song, int stopOnError) {
|
|||||||
return playPlaylistOrderNumber(fp,i);
|
return playPlaylistOrderNumber(fp,i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void syncCurrentPlayerDecodeMetadata() {
|
||||||
|
long i = 0;
|
||||||
|
Song * songPlayer = playerCurrentDecodeSong();
|
||||||
|
Song * song;
|
||||||
|
|
||||||
|
if(!songPlayer) return;
|
||||||
|
|
||||||
|
for(i=0; i<playlist.length; i++) {
|
||||||
|
song = playlist.songs[i];
|
||||||
|
|
||||||
|
if(song->type == SONG_TYPE_URL &&
|
||||||
|
0 == strcmp(song->utf8url,
|
||||||
|
songPlayer->utf8url))
|
||||||
|
{
|
||||||
|
if(song->tag) freeMpdTag(song->tag);
|
||||||
|
song->tag = mpdTagDup(songPlayer->tag);
|
||||||
|
incrPlaylistVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void syncPlayerAndPlaylist() {
|
void syncPlayerAndPlaylist() {
|
||||||
if(playlist_state!=PLAYLIST_STATE_PLAY) return;
|
if(playlist_state!=PLAYLIST_STATE_PLAY) return;
|
||||||
|
|
||||||
if(getPlayerState()==PLAYER_STATE_STOP) playPlaylistIfPlayerStopped();
|
if(getPlayerState()==PLAYER_STATE_STOP) playPlaylistIfPlayerStopped();
|
||||||
else syncPlaylistWithQueue(!playlist_queueError);
|
else syncPlaylistWithQueue(!playlist_queueError);
|
||||||
|
|
||||||
|
syncCurrentPlayerDecodeMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
int currentSongInPlaylist(FILE * fp) {
|
int currentSongInPlaylist(FILE * fp) {
|
||||||
|
@ -44,6 +44,8 @@ typedef struct _Song {
|
|||||||
|
|
||||||
typedef List SongList;
|
typedef List SongList;
|
||||||
|
|
||||||
|
Song * newNullSong();
|
||||||
|
|
||||||
Song * newSong(char * utf8url, SONG_TYPE type);
|
Song * newSong(char * utf8url, SONG_TYPE type);
|
||||||
|
|
||||||
void freeSong(Song *);
|
void freeSong(Song *);
|
||||||
|
14
src/tag.c
14
src/tag.c
@ -158,11 +158,15 @@ MpdTag * newMpdTag() {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeMpdTag(MpdTag * tag) {
|
void clearMpdTag(MpdTag * tag) {
|
||||||
if(tag->artist) free(tag->artist);
|
if(tag->artist) free(tag->artist);
|
||||||
if(tag->album) free(tag->album);
|
if(tag->album) free(tag->album);
|
||||||
if(tag->title) free(tag->title);
|
if(tag->title) free(tag->title);
|
||||||
if(tag->track) free(tag->track);
|
if(tag->track) free(tag->track);
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeMpdTag(MpdTag * tag) {
|
||||||
|
clearMpdTag(tag);
|
||||||
free(tag);
|
free(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,10 +175,10 @@ MpdTag * mpdTagDup(MpdTag * tag) {
|
|||||||
|
|
||||||
if(tag) {
|
if(tag) {
|
||||||
ret = newMpdTag();
|
ret = newMpdTag();
|
||||||
ret->artist = strdup(tag->artist);
|
if(tag->artist) ret->artist = strdup(tag->artist);
|
||||||
ret->album = strdup(tag->album);
|
if(tag->album) ret->album = strdup(tag->album);
|
||||||
ret->title = strdup(tag->title);
|
if(tag->title) ret->title = strdup(tag->title);
|
||||||
ret->track = strdup(tag->track);
|
if(tag->track) ret->track = strdup(tag->track);
|
||||||
ret->time = tag->time;
|
ret->time = tag->time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user