Initial revision 6759
[qball-mpd.git] / src / .svn / text-base / outputBuffer.c.svn-base
blobc7ff8b479ea9799bb21df440579d28408f484ad8
1 /* the Music Player Daemon (MPD)
2  * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3  * This project's homepage is: http://www.musicpd.org
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
19 #include "outputBuffer.h"
21 #include "pcm_utils.h"
22 #include "playerData.h"
23 #include "utils.h"
24 #include "log.h"
25 #include "normalize.h"
26 #include "conf.h"
28 #include <string.h>
30 static mpd_sint16 currentChunk = -1;
32 static mpd_sint8 currentMetaChunk = -1;
33 static mpd_sint8 sendMetaChunk;
35 void clearAllMetaChunkSets(OutputBuffer * cb)
37         memset(cb->metaChunkSet, 0, BUFFERED_METACHUNKS);
40 void clearOutputBuffer(OutputBuffer * cb)
42         int currentSet = 1;
44         cb->end = cb->begin;
46         /* be sure to reset metaChunkSets cause we are skipping over audio
47          * audio chunks, and thus skipping over metadata */
48         if (currentChunk >= 0 && sendMetaChunk == 0 && currentMetaChunk >= 0) {
49                 currentSet = cb->metaChunkSet[currentChunk];
50         }
51         clearAllMetaChunkSets(cb);
52         if (currentChunk >= 0 && sendMetaChunk == 0 && currentMetaChunk >= 0) {
53                 cb->metaChunkSet[currentChunk] = currentSet;
54         }
55         currentChunk = -1;
58 void flushOutputBuffer(OutputBuffer * cb)
60         if (currentChunk == cb->end) {
61                 if ((cb->end + 1) >= buffered_chunks) {
62                         cb->end = 0;
63                 }
64                 else cb->end++;
65                 currentChunk = -1;
66         }
69 int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
70                            DecoderControl * dc, int seekable, void *dataIn,
71                            long dataInLen, float time, mpd_uint16 bitRate,
72                            ReplayGainInfo * replayGainInfo)
74         mpd_uint16 dataToSend;
75         mpd_uint16 chunkLeft;
76         char *data;
77         size_t datalen;
78         static char *convBuffer;
79         static long convBufferLen;
81         if (cmpAudioFormat(&(cb->audioFormat), &(dc->audioFormat)) == 0) {
82                 data = dataIn;
83                 datalen = dataInLen;
84         } else {
85                 datalen = pcm_sizeOfConvBuffer(&(dc->audioFormat), dataInLen,
86                                                &(cb->audioFormat));
87                 if (datalen > convBufferLen) {
88                         convBuffer = xrealloc(convBuffer, datalen);
89                         convBufferLen = datalen;
90                 }
91                 data = convBuffer;
92                 datalen = pcm_convertAudioFormat(&(dc->audioFormat), dataIn,
93                                                  dataInLen, &(cb->audioFormat),
94                                                  data, &(cb->convState));
95         }
97         if (replayGainInfo && (replayGainState != REPLAYGAIN_OFF))
98                 doReplayGain(replayGainInfo, data, datalen, &cb->audioFormat);
99         else if (normalizationEnabled)
100                 normalizeData(data, datalen, &cb->audioFormat);
102         while (datalen) {
103                 if (currentChunk != cb->end) {
104                         int next = cb->end + 1;
105                         if (next >= buffered_chunks) {
106                                 next = 0;
107                         }
108                         while (cb->begin == next && !dc->stop) {
109                                 if (dc->seek) {
110                                         if (seekable) {
111                                                 return OUTPUT_BUFFER_DC_SEEK;
112                                         } else {
113                                                 dc->seekError = 1;
114                                                 dc->seek = 0;
115                                         }
116                                 }
117                                 if (!inStream ||
118                                     bufferInputStream(inStream) <= 0) {
119                                         my_usleep(10000);
120                                 }
121                         }
122                         if (dc->stop)
123                                 return OUTPUT_BUFFER_DC_STOP;
125                         currentChunk = cb->end;
126                         cb->chunkSize[currentChunk] = 0;
128                         if (sendMetaChunk) {
129                                 cb->metaChunk[currentChunk] = currentMetaChunk;
130                         } else
131                                 cb->metaChunk[currentChunk] = -1;
132                         cb->bitRate[currentChunk] = bitRate;
133                         cb->times[currentChunk] = time;
134                 }
136                 chunkLeft = CHUNK_SIZE - cb->chunkSize[currentChunk];
137                 dataToSend = datalen > chunkLeft ? chunkLeft : datalen;
139                 memcpy(cb->chunks + currentChunk * CHUNK_SIZE +
140                        cb->chunkSize[currentChunk], data, dataToSend);
141                 cb->chunkSize[currentChunk] += dataToSend;
142                 datalen -= dataToSend;
143                 data += dataToSend;
145                 if (cb->chunkSize[currentChunk] == CHUNK_SIZE) {
146                         flushOutputBuffer(cb);
147                 }
148         }
150         return 0;
153 int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag)
155         int nextChunk;
156         static MpdTag *last;
158         if (!cb->acceptMetadata || !tag) {
159                 sendMetaChunk = 0;
160                 if (last)
161                         freeMpdTag(last);
162                 last = NULL;
163                 DEBUG("copyMpdTagToOB: !acceptMetadata || !tag\n");
164                 return 0;
165         }
167         if (last && mpdTagsAreEqual(last, tag)) {
168                 DEBUG("copyMpdTagToOB: same as last\n");
169                 return 0;
170         }
172         if (last)
173                 freeMpdTag(last);
174         last = NULL;
176         nextChunk = currentMetaChunk + 1;
177         if (nextChunk >= BUFFERED_METACHUNKS)
178                 nextChunk = 0;
180         if (cb->metaChunkSet[nextChunk]) {
181                 sendMetaChunk = 0;
182                 DEBUG("copyMpdTagToOB: metachunk in use!\n");
183                 return -1;
184         }
186         sendMetaChunk = 1;
187         currentMetaChunk = nextChunk;
189         last = mpdTagDup(tag);
191         copyMpdTagToMetadataChunk(tag, &(cb->metadataChunks[currentMetaChunk]));
193         cb->metaChunkSet[nextChunk] = 1;
195         DEBUG("copyMpdTagToOB: copiedTag\n");
197         return 0;