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"
25 #include "normalize.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
)
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
;
58 void flushOutputBuffer(OutputBuffer
* cb
)
60 if (currentChunk
== cb
->end
) {
61 if ((cb
->end
+ 1) >= buffered_chunks
) {
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
;
78 static char *convBuffer
;
79 static long convBufferLen
;
81 if (cmpAudioFormat(&(cb
->audioFormat
), &(dc
->audioFormat
)) == 0) {
85 datalen
= pcm_sizeOfConvBuffer(&(dc
->audioFormat
), dataInLen
,
87 if (datalen
> convBufferLen
) {
88 convBuffer
= xrealloc(convBuffer
, datalen
);
89 convBufferLen
= datalen
;
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
);
103 if (currentChunk
!= cb
->end
) {
104 int next
= cb
->end
+ 1;
105 if (next
>= buffered_chunks
) {
108 while (cb
->begin
== next
&& !dc
->stop
) {
111 return OUTPUT_BUFFER_DC_SEEK
;
118 bufferInputStream(inStream
) <= 0) {
123 return OUTPUT_BUFFER_DC_STOP
;
125 currentChunk
= cb
->end
;
126 cb
->chunkSize
[currentChunk
] = 0;
129 cb
->metaChunk
[currentChunk
] = currentMetaChunk
;
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
;
145 if (cb
->chunkSize
[currentChunk
] == CHUNK_SIZE
) {
146 flushOutputBuffer(cb
);
153 int copyMpdTagToOutputBuffer(OutputBuffer
* cb
, MpdTag
* tag
)
158 if (!cb
->acceptMetadata
|| !tag
) {
163 DEBUG("copyMpdTagToOB: !acceptMetadata || !tag\n");
167 if (last
&& mpdTagsAreEqual(last
, tag
)) {
168 DEBUG("copyMpdTagToOB: same as last\n");
176 nextChunk
= currentMetaChunk
+ 1;
177 if (nextChunk
>= BUFFERED_METACHUNKS
)
180 if (cb
->metaChunkSet
[nextChunk
]) {
182 DEBUG("copyMpdTagToOB: metachunk in use!\n");
187 currentMetaChunk
= nextChunk
;
189 last
= mpdTagDup(tag
);
191 copyMpdTagToMetadataChunk(tag
, &(cb
->metadataChunks
[currentMetaChunk
]));
193 cb
->metaChunkSet
[nextChunk
] = 1;
195 DEBUG("copyMpdTagToOB: copiedTag\n");