From 8dd3060da4f50b8de2830fd93216b186efec7c4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 12 Apr 2010 20:36:19 +0000 Subject: [PATCH] * The AudioProducer now correctly handles late producer notices by ignoring extra notices for buffers already scheduled. * Also, the AudioSupplier/AudioReader classes now know their initial latency, and the AudioProducer is now using that one to advertize its own initial latency - this fixes late buffers on start, causing the latency to grow too large. * Cleanup here and there. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36199 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../audio/AudioAdapter.cpp | 7 + .../media_node_framework/audio/AudioAdapter.h | 10 +- .../audio/AudioChannelConverter.cpp | 49 ++++-- .../audio/AudioChannelConverter.h | 9 +- .../audio/AudioFormatConverter.cpp | 86 +++++----- .../audio/AudioFormatConverter.h | 11 +- .../audio/AudioProducer.cpp | 159 ++++++++++-------- .../audio/AudioProducer.h | 6 +- .../media_node_framework/audio/AudioReader.h | 1 + .../audio/AudioResampler.cpp | 78 +++++---- .../audio/AudioResampler.h | 9 +- .../audio/AudioSupplier.cpp | 6 +- .../audio/AudioSupplier.h | 17 +- .../audio/AudioVolumeConverter.cpp | 56 +++--- .../audio/AudioVolumeConverter.h | 9 +- .../supplier/MediaTrackAudioSupplier.cpp | 23 ++- .../supplier/MediaTrackAudioSupplier.h | 12 +- .../supplier/ProxyAudioSupplier.cpp | 45 +++-- .../mediaplayer/supplier/ProxyAudioSupplier.h | 20 ++- 19 files changed, 370 insertions(+), 243 deletions(-) diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioAdapter.cpp b/src/apps/mediaplayer/media_node_framework/audio/AudioAdapter.cpp index 4bb79984e7..161fa552c6 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioAdapter.cpp +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioAdapter.cpp @@ -77,6 +77,13 @@ AudioAdapter::~AudioAdapter() } +bigtime_t +AudioAdapter::InitialLatency() const +{ + return fSource->InitialLatency(); +} + + status_t AudioAdapter::Read(void* buffer, int64 pos, int64 frames) { diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioAdapter.h b/src/apps/mediaplayer/media_node_framework/audio/AudioAdapter.h index a33489e20c..7afe62ec0d 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioAdapter.h +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioAdapter.h @@ -1,7 +1,10 @@ /* - * Copyright © 2000-2006 Ingo Weinhold + * Copyright 2000-2006 Ingo Weinhold * All rights reserved. Distributed under the terms of the MIT licensce. */ +#ifndef AUDIO_ADAPTER_H +#define AUDIO_ADAPTER_H + /*! This AudioReader slaves an AudioConverter and an AudioResampler to convert the source data to a given format. @@ -10,21 +13,22 @@ If input and output format are the same, the overhead is quit small. */ -#ifndef AUDIO_ADAPTER_H -#define AUDIO_ADAPTER_H #include "AudioReader.h" + class AudioChannelConverter; class AudioFormatConverter; class AudioResampler; + class AudioAdapter : public AudioReader { public: AudioAdapter(AudioReader* source, const media_format& format); virtual ~AudioAdapter(); + virtual bigtime_t InitialLatency() const; virtual status_t Read(void* buffer, int64 pos, int64 frames); virtual status_t InitCheck() const; diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioChannelConverter.cpp b/src/apps/mediaplayer/media_node_framework/audio/AudioChannelConverter.cpp index f5561fa5a8..6ae51411dd 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioChannelConverter.cpp +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioChannelConverter.cpp @@ -1,7 +1,9 @@ /* - * Copyright © 2008 Stephan Aßmus + * Copyright 2008 Stephan Aßmus * All rights reserved. Distributed under the terms of the MIT licensce. */ + + #include "AudioChannelConverter.h" #include @@ -10,29 +12,15 @@ using std::nothrow; + //#define TRACE_AUDIO_CONVERTER #ifdef TRACE_AUDIO_CONVERTER -# define TRACE(x...) printf(x) +# define TRACE(x...) printf(x) #else -# define TRACE(x...) +# define TRACE(x...) #endif -AudioChannelConverter::AudioChannelConverter(AudioReader* source, - const media_format& format) - : AudioReader(format), - fSource(source) -{ - // TODO: check the format and make sure everything matches - // except for channel count -} - - -AudioChannelConverter::~AudioChannelConverter() -{ -} - - template static void convert(Type* inBuffer, Type* outBuffer, int32 inChannels, int32 outChannels, @@ -79,6 +67,31 @@ convert(Type* inBuffer, Type* outBuffer, int32 inChannels, int32 outChannels, } +// #pragma mark - + + +AudioChannelConverter::AudioChannelConverter(AudioReader* source, + const media_format& format) + : AudioReader(format), + fSource(source) +{ + // TODO: check the format and make sure everything matches + // except for channel count +} + + +AudioChannelConverter::~AudioChannelConverter() +{ +} + + +bigtime_t +AudioChannelConverter::InitialLatency() const +{ + fSource->InitialLatency(); +} + + status_t AudioChannelConverter::Read(void* outBuffer, int64 pos, int64 frames) { diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioChannelConverter.h b/src/apps/mediaplayer/media_node_framework/audio/AudioChannelConverter.h index 029ec9e562..99cbcda75e 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioChannelConverter.h +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioChannelConverter.h @@ -1,24 +1,27 @@ /* - * Copyright © 2008 Stephan Aßmus + * Copyright 2008 Stephan Aßmus * All rights reserved. Distributed under the terms of the MIT licensce. */ +#ifndef AUDIO_CHANNEL_CONVERTER_H +#define AUDIO_CHANNEL_CONVERTER_H + /*! This AudioReader just converts the source channel count into another one, e.g. 1 -> 2. Frame rate and sample format remain unchanged. */ -#ifndef AUDIO_CHANNEL_CONVERTER_H -#define AUDIO_CHANNEL_CONVERTER_H #include "AudioReader.h" + class AudioChannelConverter : public AudioReader { public: AudioChannelConverter(AudioReader* source, const media_format& format); virtual ~AudioChannelConverter(); + virtual bigtime_t InitialLatency() const; virtual status_t Read(void* buffer, int64 pos, int64 frames); virtual status_t InitCheck() const; diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioFormatConverter.cpp b/src/apps/mediaplayer/media_node_framework/audio/AudioFormatConverter.cpp index e8895bcfbd..fa01982f5b 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioFormatConverter.cpp +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioFormatConverter.cpp @@ -1,9 +1,10 @@ /* - * Copyright © 2000-2006 Ingo Weinhold - * Copyright © 2008 Stephan Aßmus + * Copyright 2000-2006 Ingo Weinhold + * Copyright 2008 Stephan Aßmus * All rights reserved. Distributed under the terms of the MIT licensce. */ + #include "AudioFormatConverter.h" #include @@ -12,44 +13,12 @@ //#define TRACE_AUDIO_CONVERTER #ifdef TRACE_AUDIO_CONVERTER -# define TRACE(x...) printf(x) +# define TRACE(x...) printf(x) #else -# define TRACE(x...) +# define TRACE(x...) #endif -AudioFormatConverter::AudioFormatConverter(AudioReader* source, uint32 format, - uint32 byte_order) - : AudioReader(), - fSource(NULL) -{ - uint32 hostByteOrder - = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN; - if (source && source->Format().type == B_MEDIA_RAW_AUDIO - && source->Format().u.raw_audio.byte_order == hostByteOrder) { - fFormat = source->Format(); - fFormat.u.raw_audio.format = format; - fFormat.u.raw_audio.byte_order = byte_order; - int32 inSampleSize = source->Format().u.raw_audio.format - & media_raw_audio_format::B_AUDIO_SIZE_MASK; - int32 outSampleSize = fFormat.u.raw_audio.format - & media_raw_audio_format::B_AUDIO_SIZE_MASK; - if (inSampleSize != outSampleSize) { - fFormat.u.raw_audio.buffer_size - = source->Format().u.raw_audio.buffer_size * outSampleSize - / inSampleSize; - } - } else - source = NULL; - fSource = source; -} - - -AudioFormatConverter::~AudioFormatConverter() -{ -} - - struct ReadFloat { inline int operator()(const void* buffer) const { // 0 == mid, -1.0 == bottom, 1.0 == top @@ -150,8 +119,7 @@ convert(const ReadT& read, const WriteT& write, } -static -void +static void swap_sample_byte_order(void* buffer, uint32 format, size_t length) { type_code type = B_ANY_TYPE; @@ -175,6 +143,48 @@ swap_sample_byte_order(void* buffer, uint32 format, size_t length) } +// #pragma mark - + + +AudioFormatConverter::AudioFormatConverter(AudioReader* source, uint32 format, + uint32 byte_order) + : + AudioReader(), + fSource(NULL) +{ + uint32 hostByteOrder + = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN; + if (source && source->Format().type == B_MEDIA_RAW_AUDIO + && source->Format().u.raw_audio.byte_order == hostByteOrder) { + fFormat = source->Format(); + fFormat.u.raw_audio.format = format; + fFormat.u.raw_audio.byte_order = byte_order; + int32 inSampleSize = source->Format().u.raw_audio.format + & media_raw_audio_format::B_AUDIO_SIZE_MASK; + int32 outSampleSize = fFormat.u.raw_audio.format + & media_raw_audio_format::B_AUDIO_SIZE_MASK; + if (inSampleSize != outSampleSize) { + fFormat.u.raw_audio.buffer_size + = source->Format().u.raw_audio.buffer_size * outSampleSize + / inSampleSize; + } + } else + source = NULL; + fSource = source; +} + + +AudioFormatConverter::~AudioFormatConverter() +{ +} + + +bigtime_t +AudioFormatConverter::InitialLatency() const +{ + fSource->InitialLatency(); +} + status_t AudioFormatConverter::Read(void* buffer, int64 pos, int64 frames) { diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioFormatConverter.h b/src/apps/mediaplayer/media_node_framework/audio/AudioFormatConverter.h index 0894fc57f2..ae169714bf 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioFormatConverter.h +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioFormatConverter.h @@ -1,25 +1,28 @@ /* - * Copyright © 2000-2006 Ingo Weinhold - * Copyright © 2008 Stephan Aßmus + * Copyright 2000-2006 Ingo Weinhold + * Copyright 2008 Stephan Aßmus * All rights reserved. Distributed under the terms of the MIT licensce. */ +#ifndef AUDIO_FORMAT_CONVERTER_H +#define AUDIO_FORMAT_CONVERTER_H + /*! This AudioReader just converts the source sample format (and byte order) into another one, e.g. LE short -> BE float. Frame rate and channel count remain unchanged. */ -#ifndef AUDIO_FORMAT_CONVERTER_H -#define AUDIO_FORMAT_CONVERTER_H #include "AudioReader.h" + class AudioFormatConverter : public AudioReader { public: AudioFormatConverter(AudioReader* source, uint32 format, uint32 byte_order); virtual ~AudioFormatConverter(); + virtual bigtime_t InitialLatency() const; virtual status_t Read(void* buffer, int64 pos, int64 frames); virtual status_t InitCheck() const; diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioProducer.cpp b/src/apps/mediaplayer/media_node_framework/audio/AudioProducer.cpp index 5f6ac5170e..1202707ddd 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioProducer.cpp +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioProducer.cpp @@ -37,13 +37,13 @@ // debugging //#define TRACE_AUDIO_PRODUCER #ifdef TRACE_AUDIO_PRODUCER -# define TRACE(x...) printf(x) -# define TRACE_BUFFER(x...) -# define ERROR(x...) fprintf(stderr, x) +# define TRACE(x...) printf(x) +# define TRACE_BUFFER(x...) +# define ERROR(x...) fprintf(stderr, x) #else -# define TRACE(x...) -# define TRACE_BUFFER(x...) -# define ERROR(x...) fprintf(stderr, x) +# define TRACE(x...) +# define TRACE_BUFFER(x...) +# define ERROR(x...) fprintf(stderr, x) #endif @@ -85,24 +85,63 @@ init_media_file(media_format format, BMediaTrack** _track) #endif // DEBUG_TO_FILE +static bigtime_t +estimate_internal_latency(const media_format& format) +{ + bigtime_t startTime = system_time(); + // calculate the number of samples per buffer + int32 sampleSize = format.u.raw_audio.format + & media_raw_audio_format::B_AUDIO_SIZE_MASK; + int32 sampleCount = format.u.raw_audio.buffer_size / sampleSize; + // alloc float buffers of this size + const int bufferCount = 10; // number of input buffers + float* buffers[bufferCount + 1]; + for (int32 i = 0; i < bufferCount + 1; i++) + buffers[i] = new float[sampleCount]; + float* outBuffer = buffers[bufferCount]; + // fill all buffers save the last one with arbitrary data and merge them + // into the last one + for (int32 i = 0; i < bufferCount; i++) { + for (int32 k = 0; k < sampleCount; k++) { + buffers[i][k] = ((float)i * (float)k) + / float(bufferCount * sampleCount); + } + } + for (int32 k = 0; k < sampleCount; k++) { + outBuffer[k] = 0; + for (int32 i = 0; i < bufferCount; i++) + outBuffer[k] += buffers[i][k]; + outBuffer[k] /= bufferCount; + } + // cleanup + for (int32 i = 0; i < bufferCount + 1; i++) + delete[] buffers[i]; + return system_time() - startTime; +} + + +// #pragma mark - + -// constructor AudioProducer::AudioProducer(const char* name, AudioSupplier* supplier, bool lowLatency) - : BMediaNode(name), - BBufferProducer(B_MEDIA_RAW_AUDIO), - BMediaEventLooper(), + : + BMediaNode(name), + BBufferProducer(B_MEDIA_RAW_AUDIO), + BMediaEventLooper(), - fBufferGroup(NULL), - fLatency(0), - fInternalLatency(0), - fLowLatency(lowLatency), - fOutputEnabled(true), - fFramesSent(0), - fStartTime(0), - fSupplier(supplier), + fBufferGroup(NULL), + fLatency(0), + fInternalLatency(0), + fLastLateNotice(0), + fNextScheduledBuffer(0), + fLowLatency(lowLatency), + fOutputEnabled(true), + fFramesSent(0), + fStartTime(0), + fSupplier(supplier), - fPeakListener(NULL) + fPeakListener(NULL) { TRACE("%p->AudioProducer::AudioProducer(%s, %p, %d)\n", this, name, supplier, lowLatency); @@ -135,9 +174,11 @@ AudioProducer::AudioProducer(const char* name, AudioSupplier* supplier, // we're not connected yet fOutput.destination = media_destination::null; fOutput.format = fPreferredFormat; + // init the audio supplier - if (fSupplier) { + if (fSupplier != NULL) { fSupplier->SetAudioProducer(this); + SetInitialLatency(fSupplier->InitialLatency()); } } @@ -359,41 +400,6 @@ AudioProducer::PrepareToConnect(const media_source& what, } -static bigtime_t -estimate_internal_latency(const media_format& format) -{ - bigtime_t startTime = system_time(); - // calculate the number of samples per buffer - int32 sampleSize = format.u.raw_audio.format - & media_raw_audio_format::B_AUDIO_SIZE_MASK; - int32 sampleCount = format.u.raw_audio.buffer_size / sampleSize; - // alloc float buffers of this size - const int bufferCount = 10; // number of input buffers - float* buffers[bufferCount + 1]; - for (int32 i = 0; i < bufferCount + 1; i++) - buffers[i] = new float[sampleCount]; - float* outBuffer = buffers[bufferCount]; - // fill all buffers save the last one with arbitrary data and merge them - // into the last one - for (int32 i = 0; i < bufferCount; i++) { - for (int32 k = 0; k < sampleCount; k++) { - buffers[i][k] = ((float)i * (float)k) - / float(bufferCount * sampleCount); - } - } - for (int32 k = 0; k < sampleCount; k++) { - outBuffer[k] = 0; - for (int32 i = 0; i < bufferCount; i++) - outBuffer[k] += buffers[i][k]; - outBuffer[k] /= bufferCount; - } - // cleanup - for (int32 i = 0; i < bufferCount + 1; i++) - delete[] buffers[i]; - return system_time() - startTime; -} - - void AudioProducer::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, @@ -490,6 +496,13 @@ AudioProducer::LateNoticeReceived(const media_source& what, bigtime_t howMuch, // If we're late, we need to catch up. Respond in a manner appropriate // to our current run mode. if (what == fOutput.source) { + // Ignore the notices for buffers we already send out (or scheduled + // their event) before we processed the last notice + if (fLastLateNotice > performanceTime) + return; + + fLastLateNotice = fNextScheduledBuffer; + if (RunMode() == B_RECORDING) { // ... } else if (RunMode() == B_INCREASE_LATENCY) { @@ -595,9 +608,10 @@ AudioProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness, TRACE("AudioProducer::HandleEvent(B_START)\n"); if (RunState() != B_STARTED) { fFramesSent = 0; - fStartTime = event->event_time; + fStartTime = event->event_time + fSupplier->InitialLatency(); printf("B_START: start time: %lld\n", fStartTime); - media_timed_event firstBufferEvent(fStartTime, + media_timed_event firstBufferEvent( + fStartTime - fSupplier->InitialLatency(), BTimedEventQueue::B_HANDLE_BUFFER); EventQueue()->AddEvent(firstBufferEvent); } @@ -607,7 +621,7 @@ printf("B_START: start time: %lld\n", fStartTime); case BTimedEventQueue::B_STOP: TRACE("AudioProducer::HandleEvent(B_STOP)\n"); EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, - BTimedEventQueue::B_HANDLE_BUFFER); + BTimedEventQueue::B_HANDLE_BUFFER); TRACE("AudioProducer::HandleEvent(B_STOP) done\n"); break; @@ -633,10 +647,10 @@ printf("B_START: start time: %lld\n", fStartTime); / (sampleSize * fOutput.format.u.raw_audio.channel_count); fFramesSent += nFrames; - bigtime_t nextEvent = fStartTime + fNextScheduledBuffer = fStartTime + bigtime_t(double(fFramesSent) * 1000000.0 - / double(fOutput.format.u.raw_audio.frame_rate)); - media_timed_event nextBufferEvent(nextEvent, + / double(fOutput.format.u.raw_audio.frame_rate)); + media_timed_event nextBufferEvent(fNextScheduledBuffer, BTimedEventQueue::B_HANDLE_BUFFER); EventQueue()->AddEvent(nextBufferEvent); } else { @@ -663,7 +677,8 @@ AudioProducer::ChangeFormat(media_format* format) { TRACE("AudioProducer::ChangeFormat()\n"); - format->u.raw_audio.buffer_size = media_raw_audio_format::wildcard.buffer_size; + format->u.raw_audio.buffer_size + = media_raw_audio_format::wildcard.buffer_size; status_t ret = _SpecializeFormat(format); if (ret != B_OK) { @@ -677,7 +692,8 @@ AudioProducer::ChangeFormat(media_format* format) return ret; } - ret = BBufferProducer::ChangeFormat(fOutput.source, fOutput.destination, format); + ret = BBufferProducer::ChangeFormat(fOutput.source, fOutput.destination, + format); if (ret != B_OK) { TRACE(" ChangeFormat(): %s\n", strerror(ret)); return ret; @@ -707,20 +723,20 @@ AudioProducer::_SpecializeFormat(media_format* format) } if (format->u.raw_audio.channel_count - == media_raw_audio_format::wildcard.channel_count) { + == media_raw_audio_format::wildcard.channel_count) { format->u.raw_audio.channel_count = 2; TRACE(" -> adjusting channel count, it was wildcard\n"); } if (format->u.raw_audio.frame_rate - == media_raw_audio_format::wildcard.frame_rate) { + == media_raw_audio_format::wildcard.frame_rate) { format->u.raw_audio.frame_rate = 44100.0; TRACE(" -> adjusting frame rate, it was wildcard\n"); } // check the buffer size, which may still be wildcarded if (format->u.raw_audio.buffer_size - == media_raw_audio_format::wildcard.buffer_size) { + == media_raw_audio_format::wildcard.buffer_size) { // pick something comfortable to suggest TRACE(" -> adjusting buffer size, it was wildcard\n"); @@ -734,7 +750,6 @@ AudioProducer::_SpecializeFormat(media_format* format) if (!fLowLatency) format->u.raw_audio.buffer_size *= 3; - } return B_OK; @@ -794,9 +809,9 @@ AudioProducer::_FillNextBuffer(bigtime_t eventTime) // number of sample in the buffer // fill in the buffer header - media_header* hdr = buffer->Header(); - hdr->type = B_MEDIA_RAW_AUDIO; - hdr->time_source = TimeSource()->ID(); + media_header* header = buffer->Header(); + header->type = B_MEDIA_RAW_AUDIO; + header->time_source = TimeSource()->ID(); buffer->SetSizeUsed(fOutput.format.u.raw_audio.buffer_size); bigtime_t performanceTime = bigtime_t(double(fFramesSent) @@ -817,9 +832,9 @@ AudioProducer::_FillNextBuffer(bigtime_t eventTime) // stamp buffer if (RunMode() == B_RECORDING) { - hdr->start_time = eventTime; + header->start_time = eventTime; } else { - hdr->start_time = fStartTime + performanceTime; + header->start_time = fStartTime + performanceTime; } #if DEBUG_TO_FILE diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioProducer.h b/src/apps/mediaplayer/media_node_framework/audio/AudioProducer.h index 9c8f5296e4..f6650054bb 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioProducer.h +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioProducer.h @@ -8,10 +8,11 @@ #ifndef AUDIO_PRODUCER_H #define AUDIO_PRODUCER_H + #include -//#include #include + class AudioSupplier; class BHandler; @@ -19,6 +20,7 @@ enum { MSG_PEAK_NOTIFICATION = 'pknt' }; + class AudioProducer : public BBufferProducer, public BMediaEventLooper { public: AudioProducer(const char* name, @@ -116,6 +118,8 @@ private: bool fUsingOurBuffers; bigtime_t fLatency; bigtime_t fInternalLatency; + bigtime_t fLastLateNotice; + bigtime_t fNextScheduledBuffer; bool fLowLatency; media_output fOutput; bool fOutputEnabled; diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioReader.h b/src/apps/mediaplayer/media_node_framework/audio/AudioReader.h index 413bb4494c..dfae0865b8 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioReader.h +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioReader.h @@ -18,6 +18,7 @@ public: void SetFormat(const media_format& format); const media_format& Format() const; + virtual bigtime_t InitialLatency() const = 0; virtual status_t Read(void* buffer, int64 pos, int64 frames) = 0; void SetOutOffset(int64 offset); diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioResampler.cpp b/src/apps/mediaplayer/media_node_framework/audio/AudioResampler.cpp index 8afea05f37..f7ad2f42b6 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioResampler.cpp +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioResampler.cpp @@ -1,7 +1,9 @@ /* - * Copyright © 2000-2006 Ingo Weinhold + * Copyright 2000-2006 Ingo Weinhold * All rights reserved. Distributed under the terms of the MIT licensce. */ + + #include "AudioResampler.h" #include @@ -11,39 +13,12 @@ //#define TRACE_AUDIO_RESAMPLER #ifdef TRACE_AUDIO_RESAMPLER -# define TRACE(x...) printf(x) +# define TRACE(x...) printf(x) #else -# define TRACE(x...) +# define TRACE(x...) #endif -AudioResampler::AudioResampler() - : AudioReader(), - fSource(NULL), - fTimeScale(1.0), - fInOffset(0) -{ -} - - -AudioResampler::AudioResampler(AudioReader* source, float frameRate, - float timeScale) - : AudioReader(), - fSource(NULL), - fTimeScale(timeScale), - fInOffset(0) -{ - SetSource(source); - if (fSource) - fFormat.u.raw_audio.frame_rate = frameRate; -} - - -AudioResampler::~AudioResampler() -{ -} - - //! Calculates the greatest common divider of /a/ and /b/. template inline T @@ -92,6 +67,45 @@ resample_linear(void* _inBuffer, void* _outBuffer, uint32 channelCount, } +// #pragma mark - + + +AudioResampler::AudioResampler() + : + AudioReader(), + fSource(NULL), + fTimeScale(1.0), + fInOffset(0) +{ +} + + +AudioResampler::AudioResampler(AudioReader* source, float frameRate, + float timeScale) + : + AudioReader(), + fSource(NULL), + fTimeScale(timeScale), + fInOffset(0) +{ + SetSource(source); + if (fSource) + fFormat.u.raw_audio.frame_rate = frameRate; +} + + +AudioResampler::~AudioResampler() +{ +} + + +bigtime_t +AudioResampler::InitialLatency() const +{ + return fSource->InitialLatency(); +} + + status_t AudioResampler::Read(void* buffer, int64 pos, int64 frames) { @@ -185,7 +199,7 @@ AudioResampler::SetSource(AudioReader* source) TRACE("AudioResampler::SetSource() - NULL source\n"); return; } - + if (source->Format().type != B_MEDIA_RAW_AUDIO) { TRACE("AudioResampler::SetSource() - not B_MEDIA_RAW_AUDIO\n"); return; @@ -197,7 +211,7 @@ AudioResampler::SetSource(AudioReader* source) TRACE("AudioResampler::SetSource() - not host byte order\n"); return; } - + float frameRate = FrameRate(); // don't overwrite previous audio frame rate fSource = source; diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioResampler.h b/src/apps/mediaplayer/media_node_framework/audio/AudioResampler.h index d88fc45708..2b9821b6e0 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioResampler.h +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioResampler.h @@ -1,7 +1,10 @@ /* - * Copyright © 2000-2006 Ingo Weinhold + * Copyright 2000-2006 Ingo Weinhold * All rights reserved. Distributed under the terms of the MIT licensce. */ +#ifndef AUDIO_RESAMPLER_H +#define AUDIO_RESAMPLER_H + /*! This AudioReader does both resampling an audio source to a different sample rate and rescaling the time, e.g. it is possible to convert the @@ -9,11 +12,10 @@ (time scale = -2). */ -#ifndef AUDIO_RESAMPLER_H -#define AUDIO_RESAMPLER_H #include "AudioReader.h" + class AudioResampler : public AudioReader { public: AudioResampler(); @@ -21,6 +23,7 @@ public: float frameRate, float timeScale = 1.0); virtual ~AudioResampler(); + virtual bigtime_t InitialLatency() const; virtual status_t Read(void* buffer, int64 pos, int64 frames); virtual status_t InitCheck() const; diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioSupplier.cpp b/src/apps/mediaplayer/media_node_framework/audio/AudioSupplier.cpp index 08529ed7df..b61625b97d 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioSupplier.cpp +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioSupplier.cpp @@ -1,6 +1,8 @@ -/* Copyright (c) 2000-2008, Ingo Weinhold , +/* Copyright 2000-2008, Ingo Weinhold , * All Rights Reserved. Distributed under the terms of the MIT license. */ + + #include "AudioSupplier.h" #include "AudioProducer.h" @@ -26,6 +28,6 @@ AudioSupplier::SetAudioProducer(AudioProducer* producer) status_t AudioSupplier::InitCheck() const { - return (fAudioProducer ? B_OK : B_NO_INIT); + return fAudioProducer ? B_OK : B_NO_INIT; } diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioSupplier.h b/src/apps/mediaplayer/media_node_framework/audio/AudioSupplier.h index a6c9fb923a..ae54cf352f 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioSupplier.h +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioSupplier.h @@ -1,11 +1,12 @@ -/* Copyright (c) 2000-2008, Ingo Weinhold , +/* Copyright 2000-2008, Ingo Weinhold , * All Rights Reserved. Distributed under the terms of the MIT license. */ +#ifndef AUDIO_SUPPLIER_H +#define AUDIO_SUPPLIER_H + /*! This class is an interface used by the AudioProducer to retreive the audio data to be played. */ -#ifndef AUDIO_SUPPLIER_H -#define AUDIO_SUPPLIER_H #include @@ -14,21 +15,23 @@ class AudioProducer; class AudioSupplier { - public: +public: AudioSupplier(); virtual ~AudioSupplier(); virtual void SetAudioProducer(AudioProducer* producer); + virtual status_t InitCheck() const; + + virtual bigtime_t InitialLatency() const = 0; + virtual status_t GetFrames(void* buffer, int64 frameCount, bigtime_t startTime, bigtime_t endTime) = 0; virtual void SetFormat(const media_format& format) = 0; - virtual status_t InitCheck() const; - - protected: +protected: AudioProducer* fAudioProducer; }; diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioVolumeConverter.cpp b/src/apps/mediaplayer/media_node_framework/audio/AudioVolumeConverter.cpp index ff78c8da32..734a87a1f5 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioVolumeConverter.cpp +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioVolumeConverter.cpp @@ -1,8 +1,9 @@ /* - * Copyright © 2008 Stephan Aßmus + * Copyright 2008 Stephan Aßmus * All rights reserved. Distributed under the terms of the MIT licensce. */ + #include "AudioVolumeConverter.h" #include @@ -13,31 +14,12 @@ //#define TRACE_AUDIO_CONVERTER #ifdef TRACE_AUDIO_CONVERTER -# define TRACE(x...) printf(x) +# define TRACE(x...) printf(x) #else -# define TRACE(x...) +# define TRACE(x...) #endif -AudioVolumeConverter::AudioVolumeConverter(AudioReader* source, float volume) - : AudioReader(), - fSource(NULL), - fVolume(volume), - fPreviousVolume(volume) -{ - if (source && source->Format().type == B_MEDIA_RAW_AUDIO) - fFormat = source->Format(); - else - source = NULL; - fSource = source; -} - - -AudioVolumeConverter::~AudioVolumeConverter() -{ -} - - template static void convert(SampleType* buffer, const int32 samples, const float volume, @@ -66,6 +48,36 @@ convert(SampleType* buffer, const int32 frames, const int32 channels, } +// #pragma mark - + + +AudioVolumeConverter::AudioVolumeConverter(AudioReader* source, float volume) + : + AudioReader(), + fSource(NULL), + fVolume(volume), + fPreviousVolume(volume) +{ + if (source && source->Format().type == B_MEDIA_RAW_AUDIO) + fFormat = source->Format(); + else + source = NULL; + fSource = source; +} + + +AudioVolumeConverter::~AudioVolumeConverter() +{ +} + + +bigtime_t +AudioVolumeConverter::InitialLatency() const +{ + return fSource->InitialLatency(); +} + + status_t AudioVolumeConverter::Read(void* buffer, int64 pos, int64 frames) { diff --git a/src/apps/mediaplayer/media_node_framework/audio/AudioVolumeConverter.h b/src/apps/mediaplayer/media_node_framework/audio/AudioVolumeConverter.h index a3293e1126..f030a946ae 100644 --- a/src/apps/mediaplayer/media_node_framework/audio/AudioVolumeConverter.h +++ b/src/apps/mediaplayer/media_node_framework/audio/AudioVolumeConverter.h @@ -1,23 +1,26 @@ /* - * Copyright © 2008 Stephan Aßmus + * Copyright 2008 Stephan Aßmus * All rights reserved. Distributed under the terms of the MIT licensce. */ +#ifndef AUDIO_VOLUME_CONVERTER_H +#define AUDIO_VOLUME_CONVERTER_H + /*! This AudioReader just filters the volume. It depends on floating point * audio format. */ -#ifndef AUDIO_VOLUME_CONVERTER_H -#define AUDIO_VOLUME_CONVERTER_H #include "AudioReader.h" + class AudioVolumeConverter : public AudioReader { public: AudioVolumeConverter(AudioReader* source, float volume = 1.0); virtual ~AudioVolumeConverter(); + virtual bigtime_t InitialLatency() const; virtual status_t Read(void* buffer, int64 pos, int64 frames); virtual status_t InitCheck() const; diff --git a/src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.cpp b/src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.cpp index cbcbe3f85e..4e4fab925d 100644 --- a/src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.cpp +++ b/src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.cpp @@ -115,7 +115,14 @@ MediaTrackAudioSupplier::Duration() const // #pragma mark - AudioReader -// Read +bigtime_t +MediaTrackAudioSupplier::InitialLatency() const +{ + // TODO: this is just a wild guess, and not really founded on anything. + return 100000; +} + + status_t MediaTrackAudioSupplier::Read(void* buffer, int64 pos, int64 frames) { @@ -518,15 +525,15 @@ MediaTrackAudioSupplier::_ReadCachedFrames(void*& dest, int64& pos, } } -// _ReadUncachedFrames -// -// Reads /frames/ frames from /position/ into /buffer/. The frames are not -// read from the cache, but read frames are cached, if possible. -// New cache buffers are stamped with the supplied time. -// If an error occurs, the untouched part of the buffer is set to 0. + +/*! Reads /frames/ frames from /position/ into /buffer/. The frames are not + read from the cache, but read frames are cached, if possible. + New cache buffers are stamped with the supplied time. + If an error occurs, the untouched part of the buffer is set to 0. +*/ status_t MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position, - int64 frames, bigtime_t time) + int64 frames, bigtime_t time) { TRACE("_ReadUncachedFrames()\n"); status_t error = B_OK; diff --git a/src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.h b/src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.h index 770d8d5223..9c484e9847 100644 --- a/src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.h +++ b/src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.h @@ -1,21 +1,24 @@ /* - * Copyright © 2000-2004 Ingo Weinhold - * Copyright © 2006-2008 Stephan Aßmus + * Copyright 2000-2004 Ingo Weinhold + * Copyright 2006-2008 Stephan Aßmus * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef MEDIA_TRACK_AUDIO_SUPPLIER_H #define MEDIA_TRACK_AUDIO_SUPPLIER_H + #include #include "AudioTrackSupplier.h" + class BMediaTrack; struct media_codec_info; struct media_format; + class MediaTrackAudioSupplier : public AudioTrackSupplier { - public: +public: MediaTrackAudioSupplier(BMediaTrack* track, int32 trackIndex); virtual ~MediaTrackAudioSupplier(); @@ -27,6 +30,7 @@ class MediaTrackAudioSupplier : public AudioTrackSupplier { // AudioReader interface // (needed to reuse the class as AudioResampler input) + virtual bigtime_t InitialLatency() const; virtual status_t Read(void* buffer, int64 pos, int64 frames); virtual status_t InitCheck() const; @@ -34,7 +38,7 @@ class MediaTrackAudioSupplier : public AudioTrackSupplier { virtual int32 TrackIndex() const { return fTrackIndex; } - private: +private: struct Buffer; void _InitFromTrack(); diff --git a/src/apps/mediaplayer/supplier/ProxyAudioSupplier.cpp b/src/apps/mediaplayer/supplier/ProxyAudioSupplier.cpp index 181deb5e46..c0818ef1b4 100644 --- a/src/apps/mediaplayer/supplier/ProxyAudioSupplier.cpp +++ b/src/apps/mediaplayer/supplier/ProxyAudioSupplier.cpp @@ -1,7 +1,9 @@ -/* - * Copyright © 2008 Stephan Aßmus +/* + * Copyright 2008 Stephan Aßmus * All Rights Reserved. Distributed under the terms of the MIT license. */ + + #include "ProxyAudioSupplier.h" #include @@ -33,8 +35,9 @@ using std::swap; struct PlayingInterval { PlayingInterval(bigtime_t startTime, bigtime_t endTime) - : start_time(startTime) - , end_time(endTime) + : + start_time(startTime), + end_time(endTime) { } @@ -47,16 +50,17 @@ struct PlayingInterval { ProxyAudioSupplier::ProxyAudioSupplier(PlaybackManager* playbackManager) - : fSupplierLock("audio supplier lock") + : + fSupplierLock("audio supplier lock"), - , fPlaybackManager(playbackManager) - , fVideoFrameRate(25.0) - , fVolume(1.0) + fPlaybackManager(playbackManager), + fVideoFrameRate(25.0), + fVolume(1.0), - , fSupplier(NULL) - , fAdapter(NULL) - , fVolumeConverter(NULL) - , fAudioResampler() + fSupplier(NULL), + fAdapter(NULL), + fVolumeConverter(NULL), + fAudioResampler() { TRACE("ProxyAudioSupplier()\n"); } @@ -70,6 +74,18 @@ ProxyAudioSupplier::~ProxyAudioSupplier() } +bigtime_t +ProxyAudioSupplier::InitialLatency() const +{ + BAutolock _(fSupplierLock); + + if (fSupplier == NULL) + return 0; + + return fSupplier->InitialLatency(); +} + + status_t ProxyAudioSupplier::GetFrames(void* buffer, int64 frameCount, bigtime_t startTime, bigtime_t endTime) @@ -100,7 +116,7 @@ ProxyAudioSupplier::GetFrames(void* buffer, int64 frameCount, ERROR("GetFrames() - zero duration audio interval! start " "time: %lld\n", intervalStartTime); break; - } + } if (!playingIntervals.AddItem(interval)) { delete interval; error = B_NO_MEMORY; @@ -182,7 +198,7 @@ ProxyAudioSupplier::SetFormat(const media_format& format) { //printf("ProxyAudioSupplier::SetFormat()\n"); #ifdef TRACE_PROXY_AUDIO_SUPPLIER - char string[256]; + char string[256]; string_for_format(format, string, 256); TRACE("SetFormat(%s)\n", string); #endif @@ -258,6 +274,7 @@ ProxyAudioSupplier::Volume() // #pragma mark - audio/video/frame/time conversion + int64 ProxyAudioSupplier::_AudioFrameForVideoFrame(int64 frame) const { diff --git a/src/apps/mediaplayer/supplier/ProxyAudioSupplier.h b/src/apps/mediaplayer/supplier/ProxyAudioSupplier.h index c48da00838..9db03cb843 100644 --- a/src/apps/mediaplayer/supplier/ProxyAudioSupplier.h +++ b/src/apps/mediaplayer/supplier/ProxyAudioSupplier.h @@ -1,10 +1,11 @@ /* - * Copyright © 2008 Stephan Aßmus + * Copyright 2008 Stephan Aßmus * All Rights Reserved. Distributed under the terms of the MIT license. */ #ifndef PROXY_AUDIO_SUPPLIER_H #define PROXY_AUDIO_SUPPLIER_H + #include #include "AudioResampler.h" @@ -26,6 +27,7 @@ public: virtual status_t GetFrames(void* buffer, int64 frameCount, bigtime_t startTime, bigtime_t endTime); + virtual bigtime_t InitialLatency() const; virtual void SetFormat(const media_format& format); virtual const media_format& Format() const; @@ -49,16 +51,16 @@ private: void* _SkipFrames(void* buffer, int64 frames) const; private: - BLocker fSupplierLock; + mutable BLocker fSupplierLock; - PlaybackManager* fPlaybackManager; - float fVideoFrameRate; - float fVolume; + PlaybackManager* fPlaybackManager; + float fVideoFrameRate; + float fVolume; - AudioTrackSupplier* fSupplier; - AudioReader* fAdapter; - AudioVolumeConverter* fVolumeConverter; - AudioResampler fAudioResampler; + AudioTrackSupplier* fSupplier; + AudioReader* fAdapter; + AudioVolumeConverter* fVolumeConverter; + AudioResampler fAudioResampler; };