Initial revision 6759
[qball-mpd.git] / src / outputBuffer.c
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
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.
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
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];
51 clearAllMetaChunkSets(cb);
52 if (currentChunk >= 0 && sendMetaChunk == 0 && currentMetaChunk >= 0) {
53 cb->metaChunkSet[currentChunk] = currentSet;
55 currentChunk = -1;
58 void flushOutputBuffer(OutputBuffer * cb)
60 if (currentChunk == cb->end) {
61 if ((cb->end + 1) >= buffered_chunks) {
62 cb->end = 0;
64 else cb->end++;
65 currentChunk = -1;
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;
91 data = convBuffer;
92 datalen = pcm_convertAudioFormat(&(dc->audioFormat), dataIn,
93 dataInLen, &(cb->audioFormat),
94 data, &(cb->convState));
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;
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;
117 if (!inStream ||
118 bufferInputStream(inStream) <= 0) {
119 my_usleep(10000);
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;
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);
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;
167 if (last && mpdTagsAreEqual(last, tag)) {
168 DEBUG("copyMpdTagToOB: same as last\n");
169 return 0;
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;
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;