diff --git a/admin-root/config.xml b/admin-root/config.xml index f3848ce7..7e6ca38e 100644 --- a/admin-root/config.xml +++ b/admin-root/config.xml @@ -327,5 +327,12 @@ text + + Always Transcode + + Codecs to always transcode, even if client plays it + + text + \ No newline at end of file diff --git a/contrib/mt-daapd.conf.templ b/contrib/mt-daapd.conf.templ index 3fab2066..163400c6 100644 --- a/contrib/mt-daapd.conf.templ +++ b/contrib/mt-daapd.conf.templ @@ -205,21 +205,6 @@ ssc_prog = @prefix@/bin/mt-daapd-ssc.sh #logfile = /var/log/mt-daapd.log -# -# art_filename (optional) -# -# There is experimental support thanks to Hiren Joshi -# (hirenj@mooh.org) for dynamically adding art to the id3v2 -# header as it is streamed (!!). If you were using a music system -# like zina or andromeda, for example, with cover art called -# "_folderOpenImage.jpg", you could use the parameter -# art_file _folderOpenImage.jpg and if the file _folderOpenImage.jpg -# was located in the same folder as the .mp3 file, it would appear -# in iTunes. Cool, eh? -# - -#art_filename = _folderOpenImage.jpg - # # rescan_interval # diff --git a/src/Makefile.am b/src/Makefile.am index b4658b24..d75e8e94 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -59,7 +59,6 @@ wavstreamer_SOURCES = wavstreamer.c mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \ webserver.h configfile.c configfile.h err.c err.h restart.c restart.h \ mp3-scanner.h mp3-scanner.c rend-unix.h \ - dynamic-art.c dynamic-art.h \ db-generic.c db-generic.h \ rxml.c rxml.h redblack.c redblack.h scan-mp3.c scan-mp4.c scan-aif.c \ scan-xml.c scan-wma.c scan-aac.c scan-aac.h scan-wav.c scan-url.c \ diff --git a/src/dynamic-art.c b/src/dynamic-art.c deleted file mode 100644 index 78eee16d..00000000 --- a/src/dynamic-art.c +++ /dev/null @@ -1,613 +0,0 @@ -/* - * $Id$ - * Dynamically merge .jpeg data into an mp3 tag - * - * Copyright (C) 2004 Hiren Joshi (hirenj@mooh.org) - * - * 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 - -#include -#include -#include -#include -#ifdef HAVE_STDINT_H -#include -#endif -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif - -#include -#include - -#include "daapd.h" -#include "conf.h" -#include "configfile.h" -#include "err.h" -#include "restart.h" -#include "mp3-scanner.h" -#include "os.h" -#include "scan-aac.h" - -#define BLKSIZE PIPE_BUF - -/* Forwards */ - -int *da_get_current_tag_info(int file_fd); -int fcopyblock(FILE *fromfp, int tofd, size_t size); - -/* For some reason, we need to lose 2 bytes from this image size - This size is everything after the APIC text in this frame. -*/ -/* APIC tag is made up from - APIC (4 bytes) - xxxx (4 bytes - Image size: raw + 16) - \0\0\0 (3 bytes) - image/jpeg (10 bytes) - \0\0\0 (3 bytes) - Image-data -*/ -#define id3v3_image_size(x) x + 14 - - -/* This size is everything after the PIC in this frame - */ -/* PIC tag is made up of - PIC (3 bytes) - xxx (3 bytes - Image size: raw + 6) - \0 (1 byte) - JPG (3 bytes) - \0\0 (2 bytes) - Image-data -*/ - -#define id3v2_image_size(x) x + 6 - - -/* For some reason we need to fudge values - Why do we need 17 bytes here? */ -#define id3v3_tag_size(x) id3v3_image_size(x) + 8 -#define id3v2_tag_size(x) id3v2_image_size(x) + 6 - -/* - * get_image_fd - * - * Get a file descriptor for a piece of cover art. - */ -int da_get_image_fd(char *filename) { - char buffer[PATH_MAX]; - char *path_end, *artfilename; - int fd; - - artfilename = conf_alloc_string("general","art_filename",NULL); - if(!artfilename) - return -1; - - strncpy(buffer,filename,sizeof(buffer)); - path_end = strrchr(buffer,PATHSEP); - if(!path_end) - return -1; - - strcpy(path_end+1,artfilename); - free(artfilename); - fd = open(buffer,O_RDONLY); - if(fd != -1) - DPRINTF(E_INF,L_ART,"Found image file %s (fd %d)\n",buffer,fd); - - return fd; -} - -/* - * get_current_tag_info - * - * Get the current tag from the file. We need to do this to determine whether we - * are dealing with an id3v2.2 or id3v2.3 tag so we can decide which artwork to - * attach to the song - */ -int *da_get_current_tag_info(int file_fd) { - unsigned char buffer[10]; - int *tag_info; - - tag_info = (int *) calloc(2,sizeof(int)); - - r_read(file_fd,buffer,10); - if (strncmp((char*)buffer,"ID3", 3) == 0 ) { - tag_info[0] = buffer[3]; - tag_info[1] = ( buffer[6] << 21 ) + ( buffer[7] << 14 ) + ( buffer[8] << 7 ) + buffer[9]; - return tag_info; - } else { - /* By default, we attach an id3v2.3 tag */ - lseek(file_fd,0,SEEK_SET); - tag_info[0] = 2; - tag_info[1] = 0; - return tag_info; - } -} - -/* - * attach_image - * - * Given an image, output and input mp3 file descriptor, attach the artwork found - * at the image file descriptor to the mp3 and stream the new id3 header to the client - * via the output file descriptor. If there is not id3 tag present, it will attach a tag - * to contain the artwork. - */ -int da_attach_image(int img_fd, int out_fd, int mp3_fd, int offset) -{ - long img_size; - int tag_size; - int *tag_info; - unsigned char buffer[4]; - struct stat sb; - - fstat(img_fd,&sb); - img_size=sb.st_size; - - DPRINTF(E_INF,L_ART,"Image appears to be %ld bytes\n",img_size); - if(img_size < 1) { - r_close(img_fd); - return 0; - } - - if (offset > (img_size + 24) ) { - lseek(mp3_fd,(offset - img_size - 24),SEEK_SET); - r_close(img_fd); - return 0; - } - - tag_info = da_get_current_tag_info(mp3_fd); - tag_size = tag_info[1]; - - DPRINTF(E_INF,L_ART,"Current tag size is %d bytes\n",tag_size); - - if (tag_info[0] == 3) { - r_write(out_fd,"ID3\x03\0\0",6); - tag_size += id3v3_tag_size(img_size); - } else { - r_write(out_fd,"ID3\x02\0\0",6); - tag_size += id3v2_tag_size(img_size); - } - - buffer[3] = tag_size & 0x7F; - buffer[2] = ( tag_size & 0x3F80 ) >> 7; - buffer[1] = ( tag_size & 0x1FC000 ) >> 14; - buffer[0] = ( tag_size & 0xFE00000 ) >> 21; - - r_write(out_fd,buffer,4); - - if (tag_info[0] == 3) { - r_write(out_fd,"APIC\0",5); - img_size = id3v3_image_size(img_size); - } else { - r_write(out_fd,"PIC",3); - img_size = id3v2_image_size(img_size); - } - buffer[0] = ( (int) img_size & 0xFF0000 ) >> 16; - buffer[1] = ( (int) img_size & 0xFF00 ) >> 8; - buffer[2] = ( (int) img_size & 0xFF ); - r_write(out_fd,buffer,3); - if (tag_info[0] == 3) { - r_write(out_fd,"\0\0\0image/jpeg\0\0\0",16); - } else { - r_write(out_fd,"\0JPG\x00\0",6); - } - lseek(img_fd,0,SEEK_SET); - copyfile(img_fd,out_fd); - DPRINTF(E_INF,L_ART,"Done copying IMG %ld\n",img_size); - r_close(img_fd); - free(tag_info); - return 0; -} - - -/** - * Rewrites the stco atom. It goes through the chunk offset atom list - * and adjusts them to take into account the 'covr' atom. - * extra_size is the amount to adjust by. - */ -off_t da_aac_rewrite_stco_atom(off_t extra_size, int out_fd, FILE *aac_fp, - off_t last_pos) -{ - int aac_fd; - struct stat sb; - unsigned char buffer[4]; - off_t file_size; - int atom_offset; - unsigned int atom_length; - off_t cur_pos; - off_t old_pos; - int i; - unsigned int num_entries; - unsigned int offset_entry; - - aac_fd = fileno(aac_fp); - - fstat(aac_fd, &sb); - file_size = sb.st_size; - - /* Drill down to the 'stco' atom which contains offsets to chunks in - the 'mdat' section. These offsets need to be readjusted. */ - atom_offset = scan_aac_drilltoatom(aac_fp, "moov:trak:mdia:minf:stbl:stco", - &atom_length); - if (atom_offset != -1) { - /* Skip flags */ - fseek(aac_fp, 4, SEEK_CUR); - - old_pos = last_pos; - cur_pos = ftell(aac_fp); - - /* Copy from last point to this point. */ - fseek(aac_fp, old_pos, SEEK_SET); - fcopyblock(aac_fp, out_fd, cur_pos - old_pos); - - /* Read number of entries */ - fread(buffer, 1, 4, aac_fp); - r_write(out_fd, buffer, 4); - - num_entries = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; - - DPRINTF(E_DBG, L_ART,"Readjusting %d 'stco' table offsets.\n", num_entries); - /* PENDING: Error check on num_entries? */ - for (i = 0; i < (int)num_entries; i++) { - fread(buffer, 1, 4, aac_fp); - offset_entry = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; - /* Adjust chunk offset. */ - offset_entry += extra_size; - buffer[3] = offset_entry & 0xFF; - buffer[2] = (offset_entry >> 8) & 0xFF; - buffer[1] = (offset_entry >> 16) & 0xFF; - buffer[0] = (offset_entry >> 24) & 0xFF; - r_write(out_fd, buffer, 4); - offset_entry = 0; - } - return ftell(aac_fp); - } else { - DPRINTF(E_LOG, L_ART,"No 'stco' atom found.\n"); - } - return last_pos; -} - -/** - * Insert a 'covr' atom. - * extra_size is the size of the atom used to adjust all parent atoms. - */ -off_t da_aac_insert_covr_atom(off_t extra_size, int out_fd, FILE *aac_fp, - off_t last_pos, off_t file_size, int img_fd) -{ - int aac_fd; - struct stat sb; - off_t old_pos; - unsigned char buffer[4]; - int atom_offset; - unsigned int atom_length; - off_t cur_pos; - char *cp; - unsigned char img_type_flag = 0; - - char *artfilename; - - if((artfilename = conf_alloc_string("general","art_filename",NULL)) == NULL) { - return 0; - } - - /* Figure out image file type since this needs to be encoded in the atom. */ - cp = strrchr(artfilename, '.'); - if (cp) { - if (!strcasecmp(cp, ".jpeg") || !strcasecmp(cp, ".jpg")) { - img_type_flag = 0x0d; - } - else if (!strcasecmp(cp, ".png")) { - img_type_flag = 0x0e; - } else { - DPRINTF(E_LOG,L_ART, "Image type '%s' not supported.\n", cp); - free(artfilename); - return 0; - } - } else { - DPRINTF(E_LOG, L_ART, "No file extension for image file.\n"); - } - free(artfilename); - - aac_fd = fileno(aac_fp); - fstat(aac_fd, &sb); - file_size = sb.st_size; - rewind(aac_fp); - - atom_offset = scan_aac_findatom(aac_fp, file_size, "moov", &atom_length); - if (atom_offset != -1) { - atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "udta", &atom_length); - if (atom_offset != -1) { - old_pos = last_pos; - cur_pos = ftell(aac_fp) - 8; - DPRINTF(E_INF,L_ART,"Found udta atom at %ld.\n", cur_pos); - fseek(aac_fp, old_pos, SEEK_SET); - fcopyblock(aac_fp, out_fd, cur_pos - old_pos); - - /* Write out new length */ - atom_length += extra_size; - buffer[3] = atom_length & 0xFF; - buffer[2] = ( atom_length >> 8 ) & 0xFF; - buffer[1] = ( atom_length >> 16 ) & 0xFF; - buffer[0] = ( atom_length >> 24 ) & 0xFF; - r_write(out_fd, buffer, 4); - - cur_pos += 4; - fseek(aac_fp, 8, SEEK_CUR); - - atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "meta", &atom_length); - if (atom_offset != -1) { - old_pos = cur_pos; - cur_pos = ftell(aac_fp) - 8; - DPRINTF(E_INF,L_ART,"Found meta atom at %ld.\n", cur_pos); - fseek(aac_fp, old_pos, SEEK_SET); - fcopyblock(aac_fp, out_fd, cur_pos - old_pos); - - /* Write out new length */ - atom_length += extra_size; - buffer[3] = atom_length & 0xFF; - buffer[2] = ( atom_length >> 8 ) & 0xFF; - buffer[1] = ( atom_length >> 16 ) & 0xFF; - buffer[0] = ( atom_length >> 24 ) & 0xFF; - r_write(out_fd, buffer, 4); - - cur_pos += 4; - fseek(aac_fp, 12, SEEK_CUR); /* "meta" atom hack. */ - - atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "ilst", &atom_length); - if (atom_offset != -1) { - old_pos = cur_pos; - cur_pos = ftell(aac_fp) - 8; - DPRINTF(E_INF,L_ART,"Found ilst atom at %ld.\n", cur_pos); - fseek(aac_fp, old_pos, SEEK_SET); - fcopyblock(aac_fp, out_fd, cur_pos - old_pos); - - old_pos = cur_pos + 4; - cur_pos += atom_length; - - /* Write out new length */ - atom_length += extra_size; - buffer[3] = atom_length & 0xFF; - buffer[2] = ( atom_length >> 8 ) & 0xFF; - buffer[1] = ( atom_length >> 16 ) & 0xFF; - buffer[0] = ( atom_length >> 24 ) & 0xFF; - r_write(out_fd, buffer, 4); - - /* Copy all 'ilst' children (all the MP4 'tags'). We will append - at the end. */ - fseek(aac_fp, old_pos, SEEK_SET); - fcopyblock(aac_fp, out_fd, cur_pos - old_pos); - cur_pos = ftell(aac_fp); - - /* Write out 'covr' atom */ - atom_length = extra_size; - buffer[3] = atom_length & 0xFF; - buffer[2] = ( atom_length >> 8 ) & 0xFF; - buffer[1] = ( atom_length >> 16 ) & 0xFF; - buffer[0] = ( atom_length >> 24 ) & 0xFF; - r_write(out_fd, buffer, 4); - - r_write(out_fd, "covr", 4); - - /* Write out 'data' atom */ - atom_length = extra_size - 8; - buffer[3] = atom_length & 0xFF; - buffer[2] = ( atom_length >> 8 ) & 0xFF; - buffer[1] = ( atom_length >> 16 ) & 0xFF; - buffer[0] = ( atom_length >> 24 ) & 0xFF; - r_write(out_fd, buffer, 4); - - r_write(out_fd, "data", 4); - - /* Write out 'data' flags */ - buffer[3] = img_type_flag; - buffer[2] = 0; - buffer[1] = 0; - buffer[0] = 0; - r_write(out_fd, buffer, 4); - - /* Reserved? Zero in any case. */ - buffer[3] = 0; - buffer[2] = 0; - buffer[1] = 0; - buffer[0] = 0; - - r_write(out_fd, buffer, 4); - - /* Now ready for the image stream. Copy it over. */ - lseek(img_fd,0,SEEK_SET); - copyfile(img_fd,out_fd); - last_pos = cur_pos; - } else { - DPRINTF(E_LOG, L_ART,"No 'ilst' atom found.\n"); - } - } else { - DPRINTF(E_LOG,L_ART, "No 'meta' atom found.\n"); - } - } else { - DPRINTF(E_LOG,L_ART, "No 'udta' atom found.\n"); - } - } else { - DPRINTF(E_LOG,L_ART, "No 'moov' atom found.\n"); - } - - /* Seek to position right after 'udta' atom. Let main() stream out the - rest. */ - lseek(aac_fd, last_pos, SEEK_SET); - - return last_pos; -} - -/* - * attach_image - * - * Given an image, output and input aac file descriptor, attach the artwork - * found at the image file descriptor to the aac and stream the new atom to - * the client via the output file descriptor. - * Currently, if the meta info atoms are non-existent, this will fail. - */ -off_t da_aac_attach_image(int img_fd, int out_fd, int aac_fd, int offset) -{ - off_t img_size; - unsigned int atom_length; - unsigned int extra_size; - off_t file_size; - unsigned char buffer[4]; - struct stat sb; - FILE *aac_fp; - off_t stco_atom_pos; - off_t ilst_atom_pos; - off_t last_pos; - - fstat(img_fd, &sb); - img_size = sb.st_size; - - DPRINTF(E_INF,L_ART,"Image size (in bytes): %ld.\n", img_size); - - /* PENDING: We can be stricter here by checking the shortest header between - PNG and JPG and using that length. */ - if (img_size < 1) { - r_close(img_fd); - return 0; - } - - /* Include extra bytes for 'covr' atom length (4) and type (4) and its - 'data' item length (4) and type (4) plus 4 bytes for the 'data' atom's - flags and 4 reserved(?) bytes. */ - extra_size = img_size + 24; - - fstat(aac_fd, &sb); - file_size = sb.st_size; - - aac_fp = fdopen(dup(aac_fd), "r"); - - stco_atom_pos = scan_aac_drilltoatom(aac_fp, - "moov:trak:mdia:minf:stbl:stco", - &atom_length); - ilst_atom_pos = scan_aac_drilltoatom(aac_fp, "moov:udta:meta:ilst", - &atom_length); - last_pos = scan_aac_drilltoatom(aac_fp, "mdat", &atom_length); - - if (last_pos != -1) { - if (offset >= last_pos) { - /* Offset is in the actual music data so don't bother processing - meta data. */ - return 0; - } - } else { - DPRINTF(E_LOG,L_ART, "No 'mdat' atom.\n"); - return 0; - } - - rewind(aac_fp); - - /* Re-adjust length of 'moov' atom. */ - last_pos = scan_aac_findatom(aac_fp, file_size, "moov", &atom_length); - if (last_pos != -1) { - /* Copy everything from up to this atom */ - rewind(aac_fp); - fcopyblock(aac_fp, out_fd, last_pos); - - /* Write out new length. */ - atom_length += extra_size; - buffer[3] = atom_length & 0xFF; - buffer[2] = ( atom_length >> 8 ) & 0xFF; - buffer[1] = ( atom_length >> 16 ) & 0xFF; - buffer[0] = ( atom_length >> 24 ) & 0xFF; - r_write(out_fd, buffer, 4); - - last_pos += 4; - } else { - DPRINTF(E_LOG,L_ART, "Could not find 'moov' atom.\n"); - return 0; - } - - if (stco_atom_pos < ilst_atom_pos) { - last_pos = da_aac_rewrite_stco_atom(extra_size, out_fd, aac_fp, last_pos); - last_pos = da_aac_insert_covr_atom(extra_size, out_fd, aac_fp, last_pos, - file_size, img_fd); - } else { - last_pos = da_aac_insert_covr_atom(extra_size, out_fd, aac_fp, last_pos, - file_size, img_fd); - last_pos = da_aac_rewrite_stco_atom(extra_size, out_fd, aac_fp, last_pos); - } - - /* Seek to position right after last atom. Let main() stream out the rest. */ - lseek(aac_fd, last_pos, SEEK_SET); - - r_close(img_fd); - fclose(aac_fp); - - return last_pos; -} - -int copyblock(int fromfd, int tofd, size_t size) { - char buf[BLKSIZE]; - int bytesread; - int totalbytes = 0; - int blocksize = BLKSIZE; - int bytesleft; - - while (totalbytes < (int) size) { - bytesleft = (int) (size - totalbytes); - if (bytesleft < BLKSIZE) { - blocksize = bytesleft; - } else { - blocksize = BLKSIZE; - } - if ((bytesread = r_read(fromfd, buf, blocksize)) < 0) - return -1; - if (bytesread == 0) - return totalbytes; - if (r_write(tofd, buf, bytesread) < 0) - return -1; - totalbytes += bytesread; - } - return totalbytes; -} - -int fcopyblock(FILE *fromfp, int tofd, size_t size) { - char buf[BLKSIZE]; - int bytesread; - int totalbytes = 0; - int blocksize = BLKSIZE; - int bytesleft; - - while (totalbytes < (int) size) { - bytesleft = (int)(size - totalbytes); - if (bytesleft < BLKSIZE) { - blocksize = bytesleft; - } else { - blocksize = BLKSIZE; - } - if ((bytesread = (int) fread(buf, 1, blocksize, fromfp)) < blocksize) { - if (ferror(fromfp)) - return -1; - } - if (r_write(tofd, buf, bytesread) < 0) - return -1; - - if (feof(fromfp)) - return 0; - totalbytes += bytesread; - } - return totalbytes; -} diff --git a/src/dynamic-art.h b/src/dynamic-art.h deleted file mode 100644 index 501128cf..00000000 --- a/src/dynamic-art.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * $Id$ - * Dynamically merge .jpeg data into an mp3 tag - * - * Copyright (C) 2004 Hiren Joshi (hirenj@mooh.org) - * - * 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 _DYNAMIC_ART_H_ -#define _DYNAMIC_ART_H_ - -int da_get_image_fd(char *filename); -int da_attach_image(int img_fd, int out_fd, int mp3_fd, int offset); -off_t da_aac_attach_image(int img_fd, int out_fd, int aac_fd, int offset); -int copyblock(int fromfd, int tofd, size_t size); -int fcopyblock(FILE *fromfp, int tofd, size_t size); - -#endif /* _DYNAMICART_H_ */ diff --git a/src/main.c b/src/main.c index 305d931b..c9bc2938 100644 --- a/src/main.c +++ b/src/main.c @@ -84,7 +84,6 @@ #include "mp3-scanner.h" #include "webserver.h" #include "restart.h" -#include "dynamic-art.h" #include "db-generic.h" #include "os.h" #include "plugin.h" diff --git a/src/plugin.c b/src/plugin.c index b9aca96c..35612436 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -51,7 +51,6 @@ #include "conf.h" #include "configfile.h" #include "db-generic.h" -#include "dynamic-art.h" #include "err.h" #include "os.h" #include "plugin.h" @@ -492,6 +491,7 @@ int pi_ssc_should_transcode(WS_CONNINFO *pwsc, char *codec) { char *native_codecs=NULL; char *user_agent=NULL; char *never_transcode = NULL; + char *always_transcode = NULL; if(!codec) { DPRINTF(E_LOG,L_PLUG,"testing transcode on null codec?\n"); @@ -518,6 +518,8 @@ int pi_ssc_should_transcode(WS_CONNINFO *pwsc, char *codec) { native_codecs = "mpeg,mp4a,wav,mp4v,alac"; } else if(strncmp(user_agent,"Roku",4)==0) { native_codecs = "mpeg,mp4a,wav,wma"; + } else if(strncmp(user_agent,"Hifidelio",9)==0) { + return FALSE; } } } @@ -531,6 +533,15 @@ int pi_ssc_should_transcode(WS_CONNINFO *pwsc, char *codec) { if(!_plugin_ssc_codecs) return FALSE; + always_transcode = conf_alloc_string("general","always_transcode",NULL); + if(always_transcode) { + if(strstr(always_transcode,codec)) { + free(always_transcode); + return TRUE; + } + free(always_transcode); + } + if(strstr(native_codecs,codec)) return FALSE; @@ -869,9 +880,6 @@ void pi_stream(WS_CONNINFO *pwsc, char *id) { off_t real_len=0; off_t file_len; off_t offset=0; - long img_size; - struct stat sb; - int img_fd; int item; /* stream out the song */ @@ -927,28 +935,9 @@ void pi_stream(WS_CONNINFO *pwsc, char *id) { } else { real_len=lseek(file_fd,0,SEEK_END); lseek(file_fd,0,SEEK_SET); - - /* Re-adjust content length for cover art */ - if((conf_isset("general","art_filename")) && - ((img_fd=da_get_image_fd(pmp3->path)) != -1)) { - fstat(img_fd, &sb); - img_size = sb.st_size; - r_close(img_fd); - - if (strncasecmp(pmp3->type,"mp3",4) ==0) { - /*PENDING*/ - } else if (strncasecmp(pmp3->type, "m4a", 4) == 0) { - real_len += img_size + 24; - - if (offset > img_size + 24) { - offset -= img_size + 24; - } - } - } - file_len = real_len - offset; - DPRINTF(E_DBG,L_WS,"Thread %d: Length of file (remaining) is %ld\n", + DPRINTF(E_DBG,L_WS,"Thread %d: Length of file (remaining): %ld\n", pwsc->threadno,(long)file_len); // DWB: fix content-type to correctly reflect data @@ -958,8 +947,15 @@ void pi_stream(WS_CONNINFO *pwsc, char *id) { ws_addresponseheader(pwsc,"Content-Type","audio/%s",pmp3->type); ws_addresponseheader(pwsc,"Content-Length","%ld",(long)file_len); - ws_addresponseheader(pwsc,"Connection","Close"); + if((ws_getrequestheader(pwsc,"user-agent")) && + (!strncmp(ws_getrequestheader(pwsc,"user-agent"), + "Hifidelio",9))) { + ws_addresponseheader(pwsc,"Connection","Keep-Alive"); + pwsc->close=0; + } else { + ws_addresponseheader(pwsc,"Connection","Close"); + } if(!offset) ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n"); @@ -977,22 +973,7 @@ void pi_stream(WS_CONNINFO *pwsc, char *id) { DPRINTF(E_WARN,L_WS,"Session %d: Streaming file '%s' to %s (offset %d)\n", session,pmp3->fname, pwsc->hostname,(long)offset); - if(!offset) - config.stats.songs_served++; /* FIXME: remove stat races */ - - if((conf_isset("general","art_filename")) && - (!offset) && - ((img_fd=da_get_image_fd(pmp3->path)) != -1)) { - if (strncasecmp(pmp3->type,"mp3",4) ==0) { - DPRINTF(E_INF,L_WS|L_ART,"Dynamic add artwork to %s (fd %d)\n", - pmp3->fname, img_fd); - da_attach_image(img_fd, pwsc->fd, file_fd, offset); - } else if (strncasecmp(pmp3->type, "m4a", 4) == 0) { - DPRINTF(E_INF,L_WS|L_ART,"Dynamic add artwork to %s (fd %d)\n", - pmp3->fname, img_fd); - da_aac_attach_image(img_fd, pwsc->fd, file_fd, offset); - } - } else if(offset) { + if(offset) { DPRINTF(E_INF,L_WS,"Seeking to offset %ld\n",(long)offset); lseek(file_fd,offset,SEEK_SET); } @@ -1012,6 +993,8 @@ void pi_stream(WS_CONNINFO *pwsc, char *id) { /* update play counts */ if(bytes_copied >= (real_len * 80 / 100)) { db_playcount_increment(NULL,pmp3->id); + if(!offset) + config.stats.songs_served++; /* FIXME: remove stat races */ } }