@@ -113,6 +113,14 @@ class MPDOpusDecoder final : public OggDecoder {
113113 */
114114 bool submitted_replay_gain = false ;
115115
116+ /* *
117+ * This is true if a SEEK command was received from
118+ * DecoderClient::Ready(). We continue reading until we see
119+ * the first packet in order to apply ReplayGain and find the
120+ * file offset of the first audio packet.
121+ */
122+ bool initial_seek = false ;
123+
116124public:
117125 explicit MPDOpusDecoder (DecoderReader &reader)
118126 :OggDecoder(reader) {}
@@ -233,8 +241,17 @@ MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet)
233241 * audio_format.channels ];
234242
235243 auto cmd = client.GetCommand ();
236- if (cmd != DecoderCommand::NONE )
244+ if (cmd != DecoderCommand::NONE ) {
245+ if (cmd == DecoderCommand::SEEK ) {
246+ /* postpone the seek until we have found the
247+ first packet with audio data, i.e. after
248+ the AutoSetFirstOffset() call */
249+ initial_seek = true ;
250+ return ;
251+ }
252+
237253 throw cmd;
254+ }
238255}
239256
240257void
@@ -277,7 +294,8 @@ MPDOpusDecoder::HandleTags(const ogg_packet &packet)
277294 if (!tag_builder.empty ()) {
278295 Tag tag = tag_builder.Commit ();
279296 auto cmd = client.SubmitTag (input_stream, std::move (tag));
280- if (cmd != DecoderCommand::NONE )
297+ if (cmd != DecoderCommand::NONE &&
298+ (cmd != DecoderCommand::SEEK || !initial_seek))
281299 throw cmd;
282300 }
283301}
@@ -299,6 +317,16 @@ MPDOpusDecoder::HandleAudio(const ogg_packet &packet)
299317 submitted_replay_gain = true ;
300318 }
301319
320+ AutoSetFirstOffset ();
321+
322+ if (initial_seek) {
323+ /* now that AutoSetFirstOffset() was called, we can do
324+ the seek (don't bother to waste time on decoding
325+ audio data) */
326+ initial_seek = false ;
327+ throw DecoderCommand::SEEK ;
328+ }
329+
302330 int nframes = opus_decode (opus_decoder,
303331 (const unsigned char *)packet.packet ,
304332 packet.bytes ,
0 commit comments