mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-26 14:13:18 -05:00
integrate server-side conversion patches, -Wall cleanups, AMD64 fixes, and xml-rpc cleanups
This commit is contained in:
parent
c33eade8ba
commit
bdd5ba39da
8
CREDITS
8
CREDITS
@ -68,3 +68,11 @@ Roger Mundt
|
||||
dirkthedaring2 (?)
|
||||
* fixes for inverted playlist
|
||||
* speedups on connect
|
||||
|
||||
Adrian Schroeter
|
||||
* fixes for AMD64
|
||||
* -Wall cleanups
|
||||
|
||||
Timo J. Rinne
|
||||
* Server-side format conversion (on-the-fly transcoding)
|
||||
|
||||
|
@ -122,7 +122,37 @@ playlist /etc/mt-daapd.playlist
|
||||
#
|
||||
#
|
||||
|
||||
extensions .mp3,.m4a,.m4p
|
||||
extensions .mp3,.m4a,.m4p,.ogg
|
||||
|
||||
#
|
||||
# ssc_extensions (optional)
|
||||
#
|
||||
# List of file extensions belonging to the files daap server
|
||||
# performs internal format conversion and present to clients
|
||||
# as WAV files. Extensions must also be present in 'extensions'
|
||||
# configuration value, or files are not probed in the first
|
||||
# place.
|
||||
#
|
||||
|
||||
ssc_extensions .ogg
|
||||
|
||||
#
|
||||
# ssc_prog (optional)
|
||||
#
|
||||
# Program that is used in server side format conversion.
|
||||
# Program must accept following command line syntax:
|
||||
# ssc_prog filename offset
|
||||
# Parameter filename is the real name of the file that is
|
||||
# to be converted and streamed, offset is number of bytes
|
||||
# that are skipped from the beginning of the _output_ file
|
||||
# before streaming is started. The resulting wav file (or
|
||||
# rest of the file after initial seek) is written to the
|
||||
# standard output by the ssc_prog program. This is typically
|
||||
# a script that is a front end for different conversion tools
|
||||
# handling different formats.
|
||||
#
|
||||
|
||||
ssc_prog /etc/mt-daapd-ssc-script
|
||||
|
||||
#
|
||||
# logfile (optional)
|
||||
|
@ -28,7 +28,7 @@ mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \
|
||||
mp3-scanner.h mp3-scanner.c playlist.c playlist.h \
|
||||
rend-unix.h lexer.l parser.y strcasestr.c strcasestr.h strsep.c \
|
||||
redblack.c redblack.h dynamic-art.c dynamic-art.h query.c query.h \
|
||||
xml-rpc.h xml-rpc.c \
|
||||
xml-rpc.h xml-rpc.c ssc.c ssc.h \
|
||||
$(PRENDSRC) $(ORENDSRC) $(HRENDSRC) $(OGGVORBISSRC)
|
||||
|
||||
EXTRA_DIST = mDNS.c mDNSClientAPI.h mDNSDebug.h mDNSPosix.c \
|
||||
|
@ -117,6 +117,8 @@ CONFIGELEMENT config_elements[] = {
|
||||
{ 1,0,0,CONFIG_TYPE_INT,"compress",(void*)&config.compress,config_emit_int },
|
||||
{ 1,0,0,CONFIG_TYPE_STRING,"playlist",(void*)&config.playlist,config_emit_string },
|
||||
{ 1,0,0,CONFIG_TYPE_STRING,"extensions",(void*)&config.extensions,config_emit_string },
|
||||
{ 1,0,0,CONFIG_TYPE_STRING,"ssc_extensions",(void*)&config.ssc_extensions,config_emit_string },
|
||||
{ 1,0,0,CONFIG_TYPE_STRING,"ssc_prog",(void*)&config.ssc_prog,config_emit_string },
|
||||
{ 1,0,0,CONFIG_TYPE_STRING,"password",(void*)&config.readpassword, config_emit_string },
|
||||
{ 1,0,0,CONFIG_TYPE_STRING,"logfile",(void*)&config.logfile, config_emit_string },
|
||||
{ 0,0,0,CONFIG_TYPE_SPECIAL,"release",(void*)VERSION,config_emit_literal },
|
||||
@ -275,6 +277,8 @@ int config_read(char *file) {
|
||||
|
||||
/* DWB: use alloced space so it can be freed without errors */
|
||||
config.extensions=strdup(".mp3");
|
||||
config.ssc_extensions=strdup("");
|
||||
config.ssc_prog=strdup("");
|
||||
|
||||
/* DWB: use alloced space so it can be freed without errors */
|
||||
config.servername=strdup("mt-daapd " VERSION);
|
||||
@ -479,6 +483,8 @@ int config_write(WS_CONNINFO *pwsc) {
|
||||
if(ws_getvar(pwsc,"password") && strlen(ws_getvar(pwsc,"password")))
|
||||
fprintf(configfile,"password\t%s\n",ws_getvar(pwsc,"password"));
|
||||
fprintf(configfile,"extensions\t%s\n",ws_getvar(pwsc,"extensions"));
|
||||
fprintf(configfile,"ssc_extensions\t%s\n",ws_getvar(pwsc,"ssc_extensions"));
|
||||
fprintf(configfile,"ssc_prog\t%s\n",ws_getvar(pwsc,"ssc_prog"));
|
||||
fprintf(configfile,"db_dir\t\t%s\n",ws_getvar(pwsc,"db_dir"));
|
||||
fprintf(configfile,"rescan_interval\t%s\n",ws_getvar(pwsc,"rescan_interval"));
|
||||
fprintf(configfile,"scan_type\t%s\n",ws_getvar(pwsc,"scan_type"));
|
||||
|
@ -64,6 +64,8 @@ typedef struct tag_config {
|
||||
char *runas; /**< Who to drop privs to (if run as root) */
|
||||
char *dbdir; /**< Where to put the db file */
|
||||
char *extensions; /**< What music file extentions to process */
|
||||
char *ssc_extensions; /**< What extensions are converted in server */
|
||||
char *ssc_prog; /**< Server side music format converter prog */
|
||||
char *artfilename; /**< What filename to merge coverart with */
|
||||
char *logfile; /**< What file to use as a logfile */
|
||||
STATS stats; /**< Stats structure (see above) */
|
||||
|
@ -23,6 +23,9 @@
|
||||
Change History (most recent first):
|
||||
|
||||
$Log$
|
||||
Revision 1.5 2005/02/21 08:10:34 rpedde
|
||||
integrate server-side conversion patches, -Wall cleanups, AMD64 fixes, and xml-rpc cleanups
|
||||
|
||||
Revision 1.4 2005/01/10 01:07:01 rpedde
|
||||
Synchronize mDNS to Apples 58.8 drop
|
||||
|
||||
@ -523,13 +526,9 @@ typedef signed char mDNSs8;
|
||||
typedef unsigned char mDNSu8;
|
||||
typedef signed short mDNSs16;
|
||||
typedef unsigned short mDNSu16;
|
||||
#if _LP64
|
||||
typedef signed int mDNSs32;
|
||||
typedef unsigned int mDNSu32;
|
||||
#else
|
||||
typedef signed long mDNSs32;
|
||||
typedef unsigned long mDNSu32;
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
typedef int32_t mDNSs32;
|
||||
typedef u_int32_t mDNSu32;
|
||||
|
||||
// To enforce useful type checking, we make mDNSInterfaceID be a pointer to a dummy struct
|
||||
// This way, mDNSInterfaceIDs can be assigned, and compared with each other, but not with other types
|
||||
|
@ -23,6 +23,9 @@
|
||||
Change History (most recent first):
|
||||
|
||||
$Log$
|
||||
Revision 1.3 2005/02/21 08:10:34 rpedde
|
||||
integrate server-side conversion patches, -Wall cleanups, AMD64 fixes, and xml-rpc cleanups
|
||||
|
||||
Revision 1.2 2005/01/10 01:07:01 rpedde
|
||||
Synchronize mDNS to Apples 58.8 drop
|
||||
|
||||
@ -151,8 +154,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
|
||||
for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
|
||||
ifr = (struct ifreq *) ptr;
|
||||
|
||||
len = GET_SA_LEN(ifr->ifr_addr);
|
||||
ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
|
||||
ptr += sizeof(*ifr);
|
||||
|
||||
// fprintf(stderr, "intf %d name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
|
||||
|
||||
|
79
src/main.c
79
src/main.c
@ -78,6 +78,7 @@
|
||||
#include "mp3-scanner.h"
|
||||
#include "webserver.h"
|
||||
#include "playlist.h"
|
||||
#include "ssc.h"
|
||||
#include "dynamic-art.h"
|
||||
|
||||
#ifndef WITHOUT_MDNS
|
||||
@ -184,6 +185,7 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
||||
|
||||
MP3FILE *pmp3;
|
||||
int file_fd;
|
||||
FILE *file_ptr; /* for possible conv filter */
|
||||
int session_id=0;
|
||||
|
||||
int img_fd;
|
||||
@ -194,6 +196,8 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
||||
off_t real_len;
|
||||
off_t file_len;
|
||||
|
||||
char *real_path;
|
||||
|
||||
int bytes_copied=0;
|
||||
|
||||
GZIP_STREAM *gz;
|
||||
@ -384,6 +388,77 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
||||
if(!pmp3) {
|
||||
DPRINTF(E_LOG,L_DAAP|L_WS|L_DB,"Could not find requested item %lu\n",item);
|
||||
ws_returnerror(pwsc,404,"File Not Found");
|
||||
} else if ((real_path=server_side_convert_path(pmp3->path)) != NULL) {
|
||||
// The file should be converted in the server side.
|
||||
DPRINTF(E_WARN,L_WS,"Thread %d: Autoconvert file %s for client\n",
|
||||
pwsc->threadno,real_path);
|
||||
file_ptr=server_side_convert_open(real_path,offset);
|
||||
if (file_ptr) {
|
||||
file_fd = fileno(file_ptr);
|
||||
} else {
|
||||
file_fd = -1;
|
||||
}
|
||||
if(file_fd == -1) {
|
||||
if (file_ptr) {
|
||||
server_side_convert_close(file_ptr);
|
||||
}
|
||||
pwsc->error=errno;
|
||||
DPRINTF(E_WARN,L_WS,
|
||||
"Thread %d: Error opening %s for conversion\n",
|
||||
pwsc->threadno,real_path);
|
||||
ws_returnerror(pwsc,404,"Not found");
|
||||
config_set_status(pwsc,session_id,NULL);
|
||||
db_dispose(pmp3);
|
||||
free(pmp3);
|
||||
free(real_path);
|
||||
} else {
|
||||
// DWB: fix content-type to correctly reflect data
|
||||
// content type (dmap tagged) should only be used on
|
||||
// dmap protocol requests, not the actually song data
|
||||
if(pmp3->type)
|
||||
ws_addresponseheader(pwsc,"Content-Type","audio/%s",
|
||||
pmp3->type);
|
||||
// Also content-length -heade would be nice, but since
|
||||
// we don't really know it here, so let's leave it out.
|
||||
ws_addresponseheader(pwsc,"Connection","Close");
|
||||
|
||||
if(!offset)
|
||||
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
||||
else {
|
||||
// This is actually against the protocol, since
|
||||
// range MUST be explicit according to HTTP-standard
|
||||
// Seems to work at least with iTunes.
|
||||
ws_addresponseheader(pwsc,
|
||||
"Content-Range","bytes %ld-*/*",
|
||||
(long)offset);
|
||||
ws_writefd(pwsc,"HTTP/1.1 206 Partial Content\r\n");
|
||||
}
|
||||
|
||||
ws_emitheaders(pwsc);
|
||||
|
||||
config_set_status(pwsc,session_id,
|
||||
"Streaming file via convert filter '%s'",
|
||||
pmp3->fname);
|
||||
DPRINTF(E_LOG,L_WS,
|
||||
"Session %d: Streaming file '%s' to %s (offset %ld)\n",
|
||||
session_id,pmp3->fname, pwsc->hostname,(long)offset);
|
||||
|
||||
if(!offset)
|
||||
config.stats.songs_served++; /* FIXME: remove stat races */
|
||||
if((bytes_copied=copyfile(file_fd,pwsc->fd)) == -1) {
|
||||
DPRINTF(E_INF,L_WS,
|
||||
"Error copying converted file to remote... %s\n",
|
||||
strerror(errno));
|
||||
} else {
|
||||
DPRINTF(E_INF,L_WS,
|
||||
"Finished streaming converted file to remote\n");
|
||||
}
|
||||
server_side_convert_close(file_ptr);
|
||||
config_set_status(pwsc,session_id,NULL);
|
||||
db_dispose(pmp3);
|
||||
free(pmp3);
|
||||
free(real_path);
|
||||
}
|
||||
} else {
|
||||
/* got the file, let's open and serve it */
|
||||
file_fd=r_open2(pmp3->path,O_RDONLY);
|
||||
@ -634,8 +709,8 @@ void *signal_handler(void *arg) {
|
||||
switch(sig) {
|
||||
case SIGCLD:
|
||||
DPRINTF(E_LOG,L_MAIN,"Got CLD signal. Reaping\n");
|
||||
while (wait(&status)) {
|
||||
};
|
||||
while (wait3(&status, WNOHANG, NULL) > 0) {
|
||||
}
|
||||
break;
|
||||
case SIGINT:
|
||||
DPRINTF(E_LOG,L_MAIN,"Got INT signal. Notifying daap server.\n");
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "err.h"
|
||||
#include "mp3-scanner.h"
|
||||
#include "playlist.h"
|
||||
#include "ssc.h"
|
||||
|
||||
#ifndef HAVE_STRCASESTR
|
||||
# include "strcasestr.h"
|
||||
@ -384,6 +385,7 @@ int scan_path(char *path) {
|
||||
char mp3_path[PATH_MAX];
|
||||
struct stat sb;
|
||||
int modified_time;
|
||||
char *ext;
|
||||
|
||||
if((current_dir=opendir(path)) == NULL) {
|
||||
DPRINTF(E_WARN,L_SCAN,"opendir: %s\n",strerror(errno));
|
||||
@ -429,9 +431,8 @@ int scan_path(char *path) {
|
||||
config.process_m3u){
|
||||
/* we found an m3u file */
|
||||
scan_static_playlist(path, pde, &sb);
|
||||
} else if (strcasestr(config.extensions,
|
||||
(char*)&pde->d_name[strlen(pde->d_name) - 4])) {
|
||||
|
||||
} else if (((ext = strrchr(pde->d_name, '.')) != NULL) &&
|
||||
(strcasestr(config.extensions, ext))) {
|
||||
/* only scan if it's been changed, or empty db */
|
||||
modified_time=sb.st_mtime;
|
||||
DPRINTF(E_DBG,L_SCAN,"FS Mod time: %d\n",modified_time);
|
||||
@ -533,8 +534,8 @@ void scan_music_file(char *path, struct dirent *pde, struct stat *psb) {
|
||||
DPRINTF(E_INF,L_SCAN,"Found music file: %s\n",pde->d_name);
|
||||
|
||||
memset((void*)&mp3file,0,sizeof(mp3file));
|
||||
mp3file.path=mp3_path;
|
||||
mp3file.fname=pde->d_name;
|
||||
mp3file.path=strdup(mp3_path);
|
||||
mp3file.fname=strdup(pde->d_name);
|
||||
if(strlen(pde->d_name) > 4)
|
||||
mp3file.type=strdup(strrchr(pde->d_name, '.') + 1);
|
||||
|
||||
@ -557,6 +558,8 @@ void scan_music_file(char *path, struct dirent *pde, struct stat *psb) {
|
||||
mp3file.time_added=psb->st_ctime;
|
||||
mp3file.time_modified=psb->st_mtime;
|
||||
|
||||
server_side_convert_set(&mp3file);
|
||||
|
||||
DPRINTF(E_DBG,L_SCAN," Date Added: %d\n",mp3file.time_added);
|
||||
|
||||
db_add(&mp3file);
|
||||
@ -942,6 +945,8 @@ int scan_get_mp3tags(char *file, MP3FILE *pmp3) {
|
||||
* Free up the tags that were dynamically allocated
|
||||
*/
|
||||
int scan_freetags(MP3FILE *pmp3) {
|
||||
MAYBEFREE(pmp3->path);
|
||||
MAYBEFREE(pmp3->fname);
|
||||
MAYBEFREE(pmp3->title);
|
||||
MAYBEFREE(pmp3->artist);
|
||||
MAYBEFREE(pmp3->album);
|
||||
@ -1769,3 +1774,4 @@ void make_composite_tags(MP3FILE *song)
|
||||
/* Ogg used to be set as an item_kind of 4. Dunno why */
|
||||
song->item_kind = 2;
|
||||
}
|
||||
|
||||
|
@ -422,6 +422,8 @@ int query_test(query_node_t* query, void* target)
|
||||
case qot_const:
|
||||
return query->left.constant;
|
||||
}
|
||||
/* should not happen */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void query_free(query_node_t* query)
|
||||
|
162
src/ssc.c
Normal file
162
src/ssc.c
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* $Id$
|
||||
* Implementation file for server side format conversion.
|
||||
*
|
||||
* Copyright (C) 2005 Timo J. Rinne (tri@iki.fi)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#define _POSIX_PTHREAD_SEMANTICS
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <id3tag.h>
|
||||
#include <limits.h>
|
||||
#include <restart.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <netinet/in.h> /* htons and friends */
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h> /* why here? For osx 10.2, of course! */
|
||||
|
||||
#include "daapd.h"
|
||||
#include "db-memory.h"
|
||||
#include "err.h"
|
||||
#include "mp3-scanner.h"
|
||||
#include "ssc.h"
|
||||
|
||||
#ifndef HAVE_STRCASESTR
|
||||
# include "strcasestr.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* If path is server side convertable, return the path to real file.
|
||||
*
|
||||
* @param path char * to the path in the database.
|
||||
*/
|
||||
char *server_side_convert_path(char *path)
|
||||
{
|
||||
char *r = NULL;
|
||||
|
||||
if (path &&
|
||||
(strlen(path) > strlen(SERVER_SIDE_CONVERT_SUFFIX)) &&
|
||||
(strcmp(path + strlen(path) - strlen(SERVER_SIDE_CONVERT_SUFFIX),
|
||||
SERVER_SIDE_CONVERT_SUFFIX) == 0)) {
|
||||
/* Lose the artificial suffix. Could use strndup here.*/
|
||||
r = strdup(path);
|
||||
r[strlen(path) - strlen(SERVER_SIDE_CONVERT_SUFFIX)] = '\0';
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file entry (otherwise complete) is such that
|
||||
* file should be converted in server end to wav-format.
|
||||
* If so, the info is modified accordingly and non-zero return
|
||||
* value is returned.
|
||||
*
|
||||
* @param song MP3FILE of the file to possibly set to server side conversion
|
||||
*/
|
||||
int server_side_convert_set(MP3FILE *pmp3)
|
||||
{
|
||||
char *fname, *path, *description, *ext;
|
||||
|
||||
if ((!config.ssc_extensions) ||
|
||||
(!config.ssc_extensions[0]) ||
|
||||
(!config.ssc_prog) ||
|
||||
(!config.ssc_prog[0]) ||
|
||||
(!pmp3->fname) ||
|
||||
(!pmp3->path) ||
|
||||
(!pmp3->type) ||
|
||||
((strlen(pmp3->fname) > strlen(SERVER_SIDE_CONVERT_SUFFIX)) &&
|
||||
(strcmp(pmp3->fname +
|
||||
strlen(pmp3->fname) -
|
||||
strlen(SERVER_SIDE_CONVERT_SUFFIX),
|
||||
SERVER_SIDE_CONVERT_SUFFIX) == 0))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (((ext = strrchr(pmp3->path, '.')) != NULL) &&
|
||||
(strcasestr(config.ssc_extensions, ext))) {
|
||||
fname = (char *)malloc(strlen(pmp3->fname) +
|
||||
strlen(SERVER_SIDE_CONVERT_SUFFIX) + 1);
|
||||
path = (char *)malloc(strlen(pmp3->path) +
|
||||
strlen(SERVER_SIDE_CONVERT_SUFFIX) + 1);
|
||||
description = (char *)malloc(strlen(pmp3->description) +
|
||||
strlen(SERVER_SIDE_CONVERT_DESCR) + 1);
|
||||
strcpy(fname, pmp3->fname);
|
||||
strcat(fname, SERVER_SIDE_CONVERT_SUFFIX);
|
||||
free(pmp3->fname);
|
||||
pmp3->fname = fname;
|
||||
strcpy(path, pmp3->path);
|
||||
strcat(path, SERVER_SIDE_CONVERT_SUFFIX);
|
||||
free(pmp3->path);
|
||||
pmp3->path = path;
|
||||
strcpy(description, pmp3->description);
|
||||
strcat(description, SERVER_SIDE_CONVERT_DESCR);
|
||||
free(pmp3->description);
|
||||
pmp3->description = description;
|
||||
free(pmp3->type);
|
||||
pmp3->type = strdup("wav");
|
||||
if (pmp3->samplerate > 0) {
|
||||
// Here we guess that it's always 16 bit stereo samples,
|
||||
// which is accurate enough for now.
|
||||
pmp3->bitrate = (pmp3->samplerate * 4 * 8) / 1000;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the source file with convert fiter.
|
||||
*
|
||||
* @param path char * to the real filename.
|
||||
* @param offset off_t to the point in file where the streaming starts.
|
||||
*/
|
||||
FILE *server_side_convert_open(char *path, off_t offset)
|
||||
{
|
||||
char *cmd;
|
||||
FILE *f;
|
||||
|
||||
cmd=(char *)malloc(strlen(config.ssc_prog) +
|
||||
strlen(path) +
|
||||
64);
|
||||
sprintf(cmd, "%s \"%s\" %ld",
|
||||
config.ssc_prog, path, (long)offset);
|
||||
f = popen(cmd, "r");
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the source file with convert fiter.
|
||||
*
|
||||
* @param FILE * returned by server_side_convert_open be closed.
|
||||
*/
|
||||
void server_side_convert_close(FILE *f)
|
||||
{
|
||||
if (f)
|
||||
pclose(f);
|
||||
return;
|
||||
}
|
||||
|
34
src/ssc.h
Normal file
34
src/ssc.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* $Id$
|
||||
* Implementation file for server side format conversion.
|
||||
*
|
||||
* Copyright (C) 2005 Timo J. Rinne (tri@iki.fi)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _SCC_H_
|
||||
#define _SCC_H_
|
||||
|
||||
#define SERVER_SIDE_CONVERT_SUFFIX ".-*-ssc-*-.wav"
|
||||
#define SERVER_SIDE_CONVERT_DESCR " (converted to WAV)"
|
||||
|
||||
extern int server_side_convert_set(MP3FILE *pmp3);
|
||||
extern char *server_side_convert_path(char *path);
|
||||
extern FILE *server_side_convert_open(char *path, off_t offset);
|
||||
extern void server_side_convert_close(FILE *f);
|
||||
|
||||
#endif /* _SCC_H_ */
|
||||
|
@ -54,7 +54,7 @@ void xml_get_playlists(WS_CONNINFO *pwsc) {
|
||||
ws_writefd(pwsc,"HTTP/1.0 200 OK\r\n");
|
||||
ws_emitheaders(pwsc);
|
||||
|
||||
ws_writefd(pwsc,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
ws_writefd(pwsc,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
|
||||
ws_writefd(pwsc,"<playlists>");
|
||||
|
||||
/* enumerate all the playlists */
|
||||
@ -99,15 +99,18 @@ void xml_get_playlistitems(WS_CONNINFO *pwsc) {
|
||||
|
||||
playlistid=atoi(playlistnum);
|
||||
|
||||
ws_writefd(pwsc,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
|
||||
ws_writefd(pwsc,"<playlist>");
|
||||
|
||||
henum=db_playlist_items_enum_begin(playlistid);
|
||||
while((itemid=db_playlist_items_enum(&henum)) != -1) {
|
||||
current=db_find(itemid);
|
||||
if(0 != current) {
|
||||
ws_writefd(pwsc,"<item>%lu</item>",itemid);
|
||||
ws_writefd(pwsc,"<item>");
|
||||
ws_writefd(pwsc,"<id>%lu</id>",itemid);
|
||||
temp=xml_entity_encode(current->title);
|
||||
ws_writefd(pwsc,"<name>%s</name>",temp);
|
||||
ws_writefd(pwsc,"</item>");
|
||||
free(temp);
|
||||
db_dispose(current);
|
||||
free(current);
|
||||
|
Loading…
x
Reference in New Issue
Block a user