155714Skris/*
255714Skris * Copyright �� 2000-2004 Ingo Weinhold <ingo_weinhold@gmx.de>
355714Skris * Copyright �� 2006-2008 Stephan A��mus <superstippi@gmx.de>
455714Skris * All rights reserved. Distributed under the terms of the MIT License.
555714Skris */
655714Skris#include "MediaTrackAudioSupplier.h"
755714Skris
855714Skris#include <new>
955714Skris#include <algorithm>
1055714Skris#include <stdio.h>
1155714Skris#include <string.h>
1255714Skris
1355714Skris#include <MediaFile.h>
1455714Skris#include <MediaTrack.h>
1555714Skris
1655714Skrisusing namespace std;
1755714Skris
1855714Skris//#define TRACE_AUDIO_SUPPLIER
1955714Skris#ifdef TRACE_AUDIO_SUPPLIER
2055714Skris# define TRACE(x...)	printf("MediaTrackAudioSupplier::" x)
2155714Skris#else
2255714Skris# define TRACE(x...)
2355714Skris#endif
2455714Skris
2555714Skris
2655714Skris// #pragma mark - Buffer
2755714Skris
2855714Skris
2955714Skrisstruct MediaTrackAudioSupplier::Buffer {
3055714Skris			void*				data;
3155714Skris			int64				offset;
3255714Skris			int64				size;
3355714Skris			bigtime_t			time_stamp;
3455714Skris
3555714Skris	static	int					CompareOffset(const void* a, const void* b);
3655714Skris};
3755714Skris
3855714Skris
3955714Skrisint
4055714SkrisMediaTrackAudioSupplier::Buffer::CompareOffset(const void* a, const void* b)
4155714Skris{
4255714Skris	const Buffer* buffer1 = *(const Buffer**)a;
4355714Skris	const Buffer* buffer2 = *(const Buffer**)b;
4455714Skris	int result = 0;
4555714Skris	if (buffer1->offset < buffer2->offset)
4655714Skris		result = -1;
4755714Skris	else if (buffer1->offset > buffer2->offset)
4855714Skris		result = 1;
4955714Skris	return result;
5055714Skris}
5155714Skris
5255714Skris
5355714Skris// #pragma mark - MediaTrackAudioSupplier
5455714Skris
5555714Skris
5655714SkrisMediaTrackAudioSupplier::MediaTrackAudioSupplier(BMediaTrack* mediaTrack,
5755714Skris		int32 trackIndex)
5855714Skris	:
59109998Smarkm	AudioTrackSupplier(),
6055714Skris	fMediaTrack(mediaTrack),
6155714Skris	fBuffer(NULL),
6255714Skris	fBufferOffset(0),
6355714Skris	fBufferSize(0),
6455714Skris	fBuffers(10),
6555714Skris	fHasKeyFrames(false),
6655714Skris	fCountFrames(0),
67109998Smarkm	fReportSeekError(true),
68109998Smarkm	fTrackIndex(trackIndex)
69109998Smarkm{
70109998Smarkm	_InitFromTrack();
71109998Smarkm}
72109998Smarkm
7368651Skris
7468651SkrisMediaTrackAudioSupplier::~MediaTrackAudioSupplier()
7568651Skris{
7668651Skris	_FreeBuffers();
7755714Skris	delete[] fBuffer;
7855714Skris}
7955714Skris
8055714Skris
8155714Skrisconst media_format&
8255714SkrisMediaTrackAudioSupplier::Format() const
8355714Skris{
8455714Skris	return AudioReader::Format();
8555714Skris}
8655714Skris
8755714Skris
8855714Skrisstatus_t
8955714SkrisMediaTrackAudioSupplier::GetEncodedFormat(media_format* format) const
9055714Skris{
9155714Skris	if (!fMediaTrack)
9259191Skris		return B_NO_INIT;
9355714Skris	return fMediaTrack->EncodedFormat(format);
9455714Skris}
9555714Skris
9655714Skris
9755714Skrisstatus_t
9855714SkrisMediaTrackAudioSupplier::GetCodecInfo(media_codec_info* info) const
9955714Skris{
10055714Skris	if (!fMediaTrack)
10155714Skris		return B_NO_INIT;
10255714Skris	return fMediaTrack->GetCodecInfo(info);
10355714Skris}
10455714Skris
10555714Skris
10655714Skrisbigtime_t
10755714SkrisMediaTrackAudioSupplier::Duration() const
10855714Skris{
10955714Skris	if (!fMediaTrack)
11055714Skris		return 0;
11155714Skris
11255714Skris	return fMediaTrack->Duration();
11355714Skris}
11455714Skris
11555714Skris
11655714Skris// #pragma mark - AudioReader
11755714Skris
11855714Skris
11955714Skrisbigtime_t
12055714SkrisMediaTrackAudioSupplier::InitialLatency() const
12155714Skris{
12255714Skris	// TODO: this is just a wild guess, and not really founded on anything.
12355714Skris	return 100000;
12455714Skris}
12555714Skris
12659191Skris
12755714Skrisstatus_t
12855714SkrisMediaTrackAudioSupplier::Read(void* buffer, int64 pos, int64 frames)
12955714Skris{
13055714Skris	TRACE("Read(%p, %lld, %lld)\n", buffer, pos,
13155714Skris		frames);
13255714Skris	TRACE("  this: %p, fOutOffset: %lld\n", this, fOutOffset);
13355714Skris
13455714Skris//printf("MediaTrackAudioSupplier::Read(%p, %lld, %lld)\n", buffer, pos, frames);
13555714Skris
13655714Skris	status_t error = InitCheck();
13755714Skris	if (error != B_OK) {
13855714Skris		TRACE("Read() InitCheck failed\n");
13955714Skris		return error;
14055714Skris	}
14155714Skris
14255714Skris	// convert pos according to our offset
14355714Skris	pos += fOutOffset;
14455714Skris	// Fill the frames after the end of the track with silence.
14555714Skris	if (fCountFrames > 0 && pos + frames > fCountFrames) {
14655714Skris		int64 size = max(0LL, fCountFrames - pos);
14755714Skris		ReadSilence(SkipFrames(buffer, size), frames - size);
14855714Skris		frames = size;
14955714Skris	}
15055714Skris
15155714Skris	TRACE("  after eliminating the frames after the track end: %p, %lld, %lld\n",
15268651Skris		buffer, pos, frames);
15355714Skris
15455714Skris#if 0
15555714Skris	const media_format& format = Format();
15655714Skris	int64 size = format.u.raw_audio.buffer_size;
15755714Skris	uint32 bytesPerFrame = format.u.raw_audio.channel_count
15855714Skris		* (format.u.raw_audio.format
15955714Skris			& media_raw_audio_format::B_AUDIO_SIZE_MASK);
16055714Skris	uint32 framesPerBuffer = size / bytesPerFrame;
16155714Skris
16255714Skris	if (fMediaTrack->CurrentFrame() != pos) {
16355714Skrisprintf("  needing to seek: %lld (%lld)\n", pos,
16455714Skris	fMediaTrack->CurrentFrame());
16555714Skris
16655714Skris		int64 keyFrame = pos;
16768651Skris		error = fMediaTrack->FindKeyFrameForFrame(&keyFrame,
16855714Skris			B_MEDIA_SEEK_CLOSEST_BACKWARD);
16955714Skris		if (error == B_OK) {
17055714Skris			error = fMediaTrack->SeekToFrame(&keyFrame,
17155714Skris				B_MEDIA_SEEK_CLOSEST_BACKWARD);
17255714Skris		}
17355714Skris		if (error != B_OK) {
17455714Skrisprintf("  error seeking to position: %lld (%lld)\n", pos,
17555714Skris	fMediaTrack->CurrentFrame());
17655714Skris
17755714Skris			return error;
17855714Skris		}
17955714Skris
18055714Skris		if (keyFrame < pos) {
18155714Skrisprintf("  need to skip %lld frames\n", pos - keyFrame);
18255714Skris			uint8 dummyBuffer[size];
18355714Skris			while (pos - keyFrame >= framesPerBuffer) {
18455714Skrisprintf("  skipped %lu frames (full buffer)\n", framesPerBuffer);
18555714Skris				int64 sizeToRead = size;
18655714Skris				fMediaTrack->ReadFrames(dummyBuffer, &sizeToRead);
18755714Skris				keyFrame += framesPerBuffer;
18855714Skris			}
18955714Skris			int64 restSize = pos - keyFrame;
19055714Skris			if (restSize > 0) {
19155714Skrisprintf("  skipped %lu frames (rest)\n", framesPerBuffer);
19255714Skris				fMediaTrack->ReadFrames(dummyBuffer, &restSize);
19355714Skris			}
19455714Skris		}
19555714Skris	}
19655714Skris	while (frames > 0) {
19755714Skrisprintf("  reading %lu frames (full buffer)\n", framesPerBuffer);
19855714Skris		int64 sizeToRead = min_c(size, frames * bytesPerFrame);
19955714Skris		fMediaTrack->ReadFrames(buffer, &sizeToRead);
20055714Skris		buffer = (uint8*)buffer + sizeToRead;
20155714Skris		frames -= framesPerBuffer;
20255714Skris	}
20355714Skrisprintf("  done\n\n");
20455714Skris
20555714Skris#else
20655714Skris	// read the cached frames
20755714Skris	bigtime_t time = system_time();
20855714Skris	if (frames > 0)
20955714Skris		_ReadCachedFrames(buffer, pos, frames, time);
21055714Skris
21155714Skris	TRACE("  after reading from cache: %p, %lld, %lld\n", buffer, pos, frames);
21255714Skris
21355714Skris	// read the remaining (uncached) frames
21455714Skris	if (frames > 0)
21555714Skris		_ReadUncachedFrames(buffer, pos, frames, time);
21655714Skris
21755714Skris#endif
21855714Skris	TRACE("Read() done\n");
21955714Skris
22068651Skris	return B_OK;
22155714Skris}
22255714Skris
22355714Skris// InitCheck
22455714Skrisstatus_t
22555714SkrisMediaTrackAudioSupplier::InitCheck() const
22655714Skris{
22755714Skris	status_t error = AudioReader::InitCheck();
22855714Skris	if (error == B_OK && (!fMediaTrack || !fBuffer))
22955714Skris		error = B_NO_INIT;
23055714Skris	return error;
23155714Skris}
23255714Skris
23355714Skris// #pragma mark -
23455714Skris
23555714Skris// _InitFromTrack
23655714Skrisvoid
237109998SmarkmMediaTrackAudioSupplier::_InitFromTrack()
23855714Skris{
23955714Skris	TRACE("_InitFromTrack()\n");
24055714Skris	// Try to suggest a big buffer size, we do a lot of caching...
24155714Skris	fFormat.u.raw_audio.buffer_size = 16384;
24255714Skris	if (fMediaTrack == NULL || fMediaTrack->DecodedFormat(&fFormat) != B_OK
24355714Skris		|| fFormat.type != B_MEDIA_RAW_AUDIO) {
24455714Skris		fMediaTrack = NULL;
24555714Skris		return;
24655714Skris	}
24755714Skris
24855714Skris	#ifdef TRACE_AUDIO_SUPPLIER
24955714Skris		char formatString[256];
25055714Skris		string_for_format(fFormat, formatString, 256);
251109998Smarkm		TRACE("_InitFromTrack(): format is: %s\n", formatString);
25255714Skris		TRACE("_InitFromTrack(): buffer size: %ld\n",
25355714Skris			fFormat.u.raw_audio.buffer_size);
25455714Skris	#endif
25555714Skris
25655714Skris	fBuffer = new (nothrow) char[fFormat.u.raw_audio.buffer_size];
25755714Skris	_AllocateBuffers();
25855714Skris
25955714Skris	// Find out, if the track has key frames: as a heuristic we
26055714Skris	// check, if the first and the second frame have the same backward
26155714Skris	// key frame.
26255714Skris	// Note: It shouldn't harm that much, if we're wrong and the
26355714Skris	// track has key frame although we found out that it has not.
26455714Skris#if 0
26555714Skris	int64 keyFrame0 = 0;
26655714Skris	int64 keyFrame1 = 1;
26755714Skris	fMediaTrack->FindKeyFrameForFrame(&keyFrame0,
26855714Skris		B_MEDIA_SEEK_CLOSEST_BACKWARD);
26955714Skris	fMediaTrack->FindKeyFrameForFrame(&keyFrame1,
27055714Skris		B_MEDIA_SEEK_CLOSEST_BACKWARD);
27155714Skris	fHasKeyFrames = (keyFrame0 == keyFrame1);
27255714Skris#else
27355714Skris	fHasKeyFrames = true;
27455714Skris#endif
27555714Skris
27655714Skris	// get the length of the track
27755714Skris	fCountFrames = fMediaTrack->CountFrames();
27855714Skris
27955714Skris	TRACE("_InitFromTrack(): keyframes: %d, frame count: %lld\n",
28055714Skris		fHasKeyFrames, fCountFrames);
28155714Skris	printf("_InitFromTrack(): keyframes: %d, frame count: %lld\n",
28255714Skris		fHasKeyFrames, fCountFrames);
28355714Skris}
28455714Skris
28555714Skris// _FramesPerBuffer
28655714Skrisint64
28755714SkrisMediaTrackAudioSupplier::_FramesPerBuffer() const
28855714Skris{
28955714Skris	int64 sampleSize = fFormat.u.raw_audio.format
29055714Skris		& media_raw_audio_format::B_AUDIO_SIZE_MASK;
29155714Skris	int64 frameSize = sampleSize * fFormat.u.raw_audio.channel_count;
29255714Skris	return fFormat.u.raw_audio.buffer_size / frameSize;
29355714Skris}
29455714Skris
29555714Skris// _CopyFrames
29655714Skris//
29755714Skris// Given two buffers starting at different frame offsets, this function
29855714Skris// copies /frames/ frames at position /position/ from the source to the
29955714Skris// target buffer.
30055714Skris// Note that no range checking is done.
30155714Skrisvoid
30255714SkrisMediaTrackAudioSupplier::_CopyFrames(void* source, int64 sourceOffset,
30355714Skris							  void* target, int64 targetOffset,
30455714Skris							  int64 position, int64 frames) const
30555714Skris{
306	int64 sampleSize = fFormat.u.raw_audio.format
307					   & media_raw_audio_format::B_AUDIO_SIZE_MASK;
308	int64 frameSize = sampleSize * fFormat.u.raw_audio.channel_count;
309	source = (char*)source + frameSize * (position - sourceOffset);
310	target = (char*)target + frameSize * (position - targetOffset);
311	memcpy(target, source, frames * frameSize);
312}
313
314// _CopyFrames
315//
316// Given two buffers starting at different frame offsets, this function
317// copies /frames/ frames at position /position/ from the source to the
318// target buffer. This version expects a cache buffer as source.
319// Note that no range checking is done.
320void
321MediaTrackAudioSupplier::_CopyFrames(Buffer* buffer,
322							  void* target, int64 targetOffset,
323							  int64 position, int64 frames) const
324{
325	_CopyFrames(buffer->data, buffer->offset, target, targetOffset, position,
326				frames);
327}
328
329// _AllocateBuffers
330//
331// Allocates a set of buffers.
332void
333MediaTrackAudioSupplier::_AllocateBuffers()
334{
335	int32 count = 10;
336	_FreeBuffers();
337	int32 bufferSize = fFormat.u.raw_audio.buffer_size;
338	char* data = new (nothrow) char[bufferSize * count];
339	for (; count > 0; count--) {
340		Buffer* buffer = new (nothrow) Buffer;
341		if (!buffer || !fBuffers.AddItem(buffer)) {
342			delete buffer;
343			if (fBuffers.CountItems() == 0)
344				delete[] data;
345			return;
346		}
347		buffer->data = data;
348		data += bufferSize;
349		buffer->offset = 0;
350		buffer->size = 0;
351		buffer->time_stamp = 0;
352	}
353}
354
355// _FreeBuffers
356//
357// Frees the allocated buffers.
358void
359MediaTrackAudioSupplier::_FreeBuffers()
360{
361	if (fBuffers.CountItems() > 0) {
362		delete[] (char*)_BufferAt(0)->data;
363		for (int32 i = 0; Buffer* buffer = _BufferAt(i); i++)
364			delete buffer;
365		fBuffers.MakeEmpty();
366	}
367}
368
369// _BufferAt
370//
371// Returns the buffer at index /index/.
372MediaTrackAudioSupplier::Buffer*
373MediaTrackAudioSupplier::_BufferAt(int32 index) const
374{
375	return (Buffer*)fBuffers.ItemAt(index);
376}
377
378// _FindBufferAtFrame
379//
380// If any buffer starts at offset /frame/, it is returned, NULL otherwise.
381MediaTrackAudioSupplier::Buffer*
382MediaTrackAudioSupplier::_FindBufferAtFrame(int64 frame) const
383{
384	Buffer* buffer = NULL;
385	for (int32 i = 0;
386		 ((buffer = _BufferAt(i))) && buffer->offset != frame;
387		 i++);
388	return buffer;
389}
390
391// _FindUnusedBuffer
392//
393// Returns the first unused buffer or NULL if all buffers are used.
394MediaTrackAudioSupplier::Buffer*
395MediaTrackAudioSupplier::_FindUnusedBuffer() const
396{
397	Buffer* buffer = NULL;
398	for (int32 i = 0; ((buffer = _BufferAt(i))) && buffer->size != 0; i++)
399		;
400	return buffer;
401}
402
403// _FindUsableBuffer
404//
405// Returns either an unused buffer or, if all buffers are used, the least
406// recently used buffer.
407// In every case a buffer is returned.
408MediaTrackAudioSupplier::Buffer*
409MediaTrackAudioSupplier::_FindUsableBuffer() const
410{
411	Buffer* result = _FindUnusedBuffer();
412	if (!result) {
413		// find the least recently used buffer.
414		result = _BufferAt(0);
415		for (int32 i = 1; Buffer* buffer = _BufferAt(i); i++) {
416			if (buffer->time_stamp < result->time_stamp)
417				result = buffer;
418		}
419	}
420	return result;
421}
422
423// _FindUsableBufferFor
424//
425// In case there already exists a buffer that starts at position this
426// one is returned. Otherwise the function returns either an unused
427// buffer or, if all buffers are used, the least recently used buffer.
428// In every case a buffer is returned.
429MediaTrackAudioSupplier::Buffer*
430MediaTrackAudioSupplier::_FindUsableBufferFor(int64 position) const
431{
432	Buffer* buffer = _FindBufferAtFrame(position);
433	if (buffer == NULL)
434		buffer = _FindUsableBuffer();
435	return buffer;
436}
437
438// _GetBuffersFor
439//
440// Adds pointers to all buffers to the list that contain data of the
441// supplied interval.
442void
443MediaTrackAudioSupplier::_GetBuffersFor(BList& buffers, int64 position,
444								 int64 frames) const
445{
446	buffers.MakeEmpty();
447	for (int32 i = 0; Buffer* buffer = _BufferAt(i); i++) {
448		// Calculate the intersecting interval and add the buffer if it is
449		// not empty.
450		int32 startFrame = max(position, buffer->offset);
451		int32 endFrame = min(position + frames, buffer->offset + buffer->size);
452		if (startFrame < endFrame)
453			buffers.AddItem(buffer);
454	}
455}
456
457// _TouchBuffer
458//
459// Sets a buffer's time stamp to the current system time.
460void
461MediaTrackAudioSupplier::_TouchBuffer(Buffer* buffer)
462{
463	buffer->time_stamp = system_time();
464}
465
466// _ReadBuffer
467//
468// Read a buffer from the current position (which is supplied in /position/)
469// into /buffer/. The buffer's time stamp is set to the current system time.
470status_t
471MediaTrackAudioSupplier::_ReadBuffer(Buffer* buffer, int64 position)
472{
473	return _ReadBuffer(buffer, position, system_time());
474}
475
476// _ReadBuffer
477//
478// Read a buffer from the current position (which is supplied in /position/)
479// into /buffer/. The buffer's time stamp is set to the supplied time.
480status_t
481MediaTrackAudioSupplier::_ReadBuffer(Buffer* buffer, int64 position,
482	bigtime_t time)
483{
484	status_t error = fMediaTrack->ReadFrames(buffer->data, &buffer->size);
485
486	TRACE("_ReadBuffer(%p, %lld): %s\n", buffer->data, buffer->size,
487		strerror(error));
488
489	buffer->offset = position;
490	buffer->time_stamp = time;
491	if (error != B_OK)
492		buffer->size = 0;
493	return error;
494}
495
496// _ReadCachedFrames
497//
498// Tries to read as much as possible data from the cache. The supplied
499// buffer pointer as well as position and number of frames are adjusted
500// accordingly. The used cache buffers are stamped with the supplied
501// time.
502void
503MediaTrackAudioSupplier::_ReadCachedFrames(void*& dest, int64& pos,
504	int64& frames, bigtime_t time)
505{
506	// Get a list of all cache buffers that contain data of the interval,
507	// and sort it.
508	BList buffers(10);
509	_GetBuffersFor(buffers, pos, frames);
510	buffers.SortItems(Buffer::CompareOffset);
511	// Step forward through the list of cache buffers and try to read as
512	// much data from the beginning as possible.
513	for (int32 i = 0; Buffer* buffer = (Buffer*)buffers.ItemAt(i); i++) {
514		if (buffer->offset <= pos && buffer->offset + buffer->size > pos) {
515			// read from the beginning
516			int64 size = min(frames, buffer->offset + buffer->size - pos);
517			_CopyFrames(buffer->data, buffer->offset, dest, pos, pos, size);
518			pos += size;
519			frames -= size;
520			dest = SkipFrames(dest, size);
521			buffer->time_stamp = time;
522		}
523	}
524	// Step backward through the list of cache buffers and try to read as
525	// much data from the end as possible.
526	for (int32 i = buffers.CountItems() - 1;
527		 Buffer* buffer = (Buffer*)buffers.ItemAt(i);
528		 i++) {
529		if (buffer->offset < pos + frames
530			&& buffer->offset + buffer->size >= pos + frames) {
531			// read from the end
532			int64 size = min(frames, pos + frames - buffer->offset);
533			_CopyFrames(buffer->data, buffer->offset, dest, pos,
534						pos + frames - size, size);
535			frames -= size;
536			buffer->time_stamp = time;
537		}
538	}
539}
540
541
542/*!	Reads /frames/ frames from /position/ into /buffer/. The frames are not
543	read from the cache, but read frames are cached, if possible.
544	New cache buffers are stamped with the supplied time.
545	If an error occurs, the untouched part of the buffer is set to 0.
546*/
547status_t
548MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position,
549	int64 frames, bigtime_t time)
550{
551	TRACE("_ReadUncachedFrames()\n");
552	status_t error = B_OK;
553	// seek to the position
554	int64 currentPos = position;
555	if (frames > 0) {
556		error = _SeekToKeyFrameBackward(currentPos);
557		TRACE("_ReadUncachedFrames() - seeked to position: %lld\n", currentPos);
558//		if (position - currentPos > 100000)
559//			printf("MediaTrackAudioSupplier::_ReadUncachedFrames() - "
560//				"keyframe was far away: %lld -> %lld\n", position, currentPos);
561	}
562	// read the frames
563	// TODO: Calculate timeout, 0.25 times duration of "frames" seems good.
564	bigtime_t timeout = 10000;
565	while (error == B_OK && frames > 0) {
566		Buffer* cacheBuffer = _FindUsableBufferFor(currentPos);
567		TRACE("_ReadUncachedFrames() - usable buffer found: %p, "
568			"position: %lld/%lld\n", cacheBuffer, currentPos, position);
569		error = _ReadBuffer(cacheBuffer, currentPos, time);
570		if (error == B_OK) {
571			int64 size = min(position + frames,
572				cacheBuffer->offset + cacheBuffer->size) - position;
573			if (size > 0) {
574				_CopyFrames(cacheBuffer, buffer, position, position, size);
575				buffer = SkipFrames(buffer, size);
576				position += size;
577				frames -= size;
578			}
579			currentPos += cacheBuffer->size;
580		}
581		if (system_time() - time > timeout) {
582			error = B_TIMED_OUT;
583			break;
584		}
585	}
586
587#if 0
588	// Ensure that all frames up to the next key frame are cached.
589	// This avoids, that each read reaches the BMediaTrack.
590	if (error == B_OK) {
591		int64 nextKeyFrame = currentPos;
592		if (_FindKeyFrameForward(nextKeyFrame) == B_OK) {
593			while (currentPos < nextKeyFrame) {
594				// Check, if data at this position are cache.
595				// If not read it.
596				Buffer* cacheBuffer = _FindBufferAtFrame(currentPos);
597				if (!cacheBuffer || cacheBuffer->size == 0) {
598					cacheBuffer = _FindUsableBufferFor(currentPos);
599					if (_ReadBuffer(cacheBuffer, currentPos, time) != B_OK)
600						break;
601				}
602				if (cacheBuffer)
603					currentPos += cacheBuffer->size;
604			}
605		}
606	}
607#endif
608
609	// on error fill up the buffer with silence
610	if (error != B_OK && frames > 0)
611		ReadSilence(buffer, frames);
612	return error;
613}
614
615// _FindKeyFrameForward
616status_t
617MediaTrackAudioSupplier::_FindKeyFrameForward(int64& position)
618{
619	status_t error = B_OK;
620	if (fHasKeyFrames) {
621		error = fMediaTrack->FindKeyFrameForFrame(
622			&position, B_MEDIA_SEEK_CLOSEST_FORWARD);
623	} else {
624		int64 framesPerBuffer = _FramesPerBuffer();
625		position += framesPerBuffer - 1;
626		position = position % framesPerBuffer;
627	}
628	return error;
629}
630
631// _FindKeyFrameBackward
632status_t
633MediaTrackAudioSupplier::_FindKeyFrameBackward(int64& position)
634{
635	status_t error = B_OK;
636	if (fHasKeyFrames) {
637		error = fMediaTrack->FindKeyFrameForFrame(
638			&position, B_MEDIA_SEEK_CLOSEST_BACKWARD);
639	} else
640		position -= position % _FramesPerBuffer();
641	return error;
642}
643
644#if 0
645// _SeekToKeyFrameForward
646status_t
647MediaTrackAudioSupplier::_SeekToKeyFrameForward(int64& position)
648{
649	if (position == fMediaTrack->CurrentFrame())
650		return B_OK;
651
652	status_t error = B_OK;
653	if (fHasKeyFrames) {
654		#ifdef TRACE_AUDIO_SUPPLIER
655		int64 oldPosition = position;
656		#endif
657		error = fMediaTrack->SeekToFrame(&position,
658			B_MEDIA_SEEK_CLOSEST_FORWARD);
659		TRACE("_SeekToKeyFrameForward() - seek to key frame forward: "
660			"%lld -> %lld (%lld)\n", oldPosition, position,
661			fMediaTrack->CurrentFrame());
662	} else {
663		_FindKeyFrameForward(position);
664		error = fMediaTrack->SeekToFrame(&position);
665	}
666	return error;
667}
668#endif
669
670// _SeekToKeyFrameBackward
671status_t
672MediaTrackAudioSupplier::_SeekToKeyFrameBackward(int64& position)
673{
674	int64 currentPosition = fMediaTrack->CurrentFrame();
675	if (position == currentPosition)
676		return B_OK;
677
678	status_t error = B_OK;
679	if (fHasKeyFrames) {
680		int64 wantedPosition = position;
681		error = fMediaTrack->FindKeyFrameForFrame(&position,
682			B_MEDIA_SEEK_CLOSEST_BACKWARD);
683		if (error == B_OK && currentPosition > position
684			&& currentPosition < wantedPosition) {
685			// The current position is before the wanted position,
686			// but later than the keyframe, so seeking is worse.
687			position = currentPosition;
688			return B_OK;
689		}
690		if (error == B_OK && position > wantedPosition) {
691			// We asked to seek backwards, but the extractor seeked
692			// forwards! Returning an error here will cause silence
693			// to be produced.
694			return B_ERROR;
695		}
696		if (error == B_OK)
697			error = fMediaTrack->SeekToFrame(&position, 0);
698		if (error != B_OK) {
699			position = fMediaTrack->CurrentFrame();
700//			if (fReportSeekError) {
701				printf("  seek to key frame backward: %lld -> %lld (%lld) "
702					"- %s\n", wantedPosition, position,
703					fMediaTrack->CurrentFrame(), strerror(error));
704				fReportSeekError = false;
705//			}
706		} else {
707			fReportSeekError = true;
708		}
709	} else {
710		_FindKeyFrameBackward(position);
711		error = fMediaTrack->SeekToFrame(&position);
712	}
713	return error;
714}
715
716