* 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
This commit is contained in:
Axel Dörfler
2010-04-12 20:36:19 +00:00
parent 02af02f93a
commit 8dd3060da4
19 changed files with 370 additions and 243 deletions
@@ -77,6 +77,13 @@ AudioAdapter::~AudioAdapter()
} }
bigtime_t
AudioAdapter::InitialLatency() const
{
return fSource->InitialLatency();
}
status_t status_t
AudioAdapter::Read(void* buffer, int64 pos, int64 frames) AudioAdapter::Read(void* buffer, int64 pos, int64 frames)
{ {
@@ -1,7 +1,10 @@
/* /*
* Copyright © 2000-2006 Ingo Weinhold <[email protected]> * Copyright 2000-2006 Ingo Weinhold <[email protected]>
* All rights reserved. Distributed under the terms of the MIT licensce. * 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 /*! This AudioReader slaves an AudioConverter and an AudioResampler
to convert the source data to a given format. 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. If input and output format are the same, the overhead is quit small.
*/ */
#ifndef AUDIO_ADAPTER_H
#define AUDIO_ADAPTER_H
#include "AudioReader.h" #include "AudioReader.h"
class AudioChannelConverter; class AudioChannelConverter;
class AudioFormatConverter; class AudioFormatConverter;
class AudioResampler; class AudioResampler;
class AudioAdapter : public AudioReader { class AudioAdapter : public AudioReader {
public: public:
AudioAdapter(AudioReader* source, AudioAdapter(AudioReader* source,
const media_format& format); const media_format& format);
virtual ~AudioAdapter(); virtual ~AudioAdapter();
virtual bigtime_t InitialLatency() const;
virtual status_t Read(void* buffer, int64 pos, int64 frames); virtual status_t Read(void* buffer, int64 pos, int64 frames);
virtual status_t InitCheck() const; virtual status_t InitCheck() const;
@@ -1,7 +1,9 @@
/* /*
* Copyright © 2008 Stephan Aßmus <[email protected]> * Copyright 2008 Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT licensce. * All rights reserved. Distributed under the terms of the MIT licensce.
*/ */
#include "AudioChannelConverter.h" #include "AudioChannelConverter.h"
#include <new> #include <new>
@@ -10,29 +12,15 @@
using std::nothrow; using std::nothrow;
//#define TRACE_AUDIO_CONVERTER //#define TRACE_AUDIO_CONVERTER
#ifdef TRACE_AUDIO_CONVERTER #ifdef TRACE_AUDIO_CONVERTER
# define TRACE(x...) printf(x) # define TRACE(x...) printf(x)
#else #else
# define TRACE(x...) # define TRACE(x...)
#endif #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<typename Type, typename BigType> template<typename Type, typename BigType>
static void static void
convert(Type* inBuffer, Type* outBuffer, int32 inChannels, int32 outChannels, 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 status_t
AudioChannelConverter::Read(void* outBuffer, int64 pos, int64 frames) AudioChannelConverter::Read(void* outBuffer, int64 pos, int64 frames)
{ {
@@ -1,24 +1,27 @@
/* /*
* Copyright © 2008 Stephan Aßmus <[email protected]> * Copyright 2008 Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT licensce. * 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 /*! This AudioReader just converts the source channel count
into another one, e.g. 1 -> 2. Frame rate and sample format into another one, e.g. 1 -> 2. Frame rate and sample format
remain unchanged. remain unchanged.
*/ */
#ifndef AUDIO_CHANNEL_CONVERTER_H
#define AUDIO_CHANNEL_CONVERTER_H
#include "AudioReader.h" #include "AudioReader.h"
class AudioChannelConverter : public AudioReader { class AudioChannelConverter : public AudioReader {
public: public:
AudioChannelConverter(AudioReader* source, AudioChannelConverter(AudioReader* source,
const media_format& format); const media_format& format);
virtual ~AudioChannelConverter(); virtual ~AudioChannelConverter();
virtual bigtime_t InitialLatency() const;
virtual status_t Read(void* buffer, int64 pos, int64 frames); virtual status_t Read(void* buffer, int64 pos, int64 frames);
virtual status_t InitCheck() const; virtual status_t InitCheck() const;
@@ -1,9 +1,10 @@
/* /*
* Copyright © 2000-2006 Ingo Weinhold <[email protected]> * Copyright 2000-2006 Ingo Weinhold <[email protected]>
* Copyright © 2008 Stephan Aßmus <[email protected]> * Copyright 2008 Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT licensce. * All rights reserved. Distributed under the terms of the MIT licensce.
*/ */
#include "AudioFormatConverter.h" #include "AudioFormatConverter.h"
#include <ByteOrder.h> #include <ByteOrder.h>
@@ -12,44 +13,12 @@
//#define TRACE_AUDIO_CONVERTER //#define TRACE_AUDIO_CONVERTER
#ifdef TRACE_AUDIO_CONVERTER #ifdef TRACE_AUDIO_CONVERTER
# define TRACE(x...) printf(x) # define TRACE(x...) printf(x)
#else #else
# define TRACE(x...) # define TRACE(x...)
#endif #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 { struct ReadFloat {
inline int operator()(const void* buffer) const { inline int operator()(const void* buffer) const {
// 0 == mid, -1.0 == bottom, 1.0 == top // 0 == mid, -1.0 == bottom, 1.0 == top
@@ -150,8 +119,7 @@ convert(const ReadT& read, const WriteT& write,
} }
static static void
void
swap_sample_byte_order(void* buffer, uint32 format, size_t length) swap_sample_byte_order(void* buffer, uint32 format, size_t length)
{ {
type_code type = B_ANY_TYPE; 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 status_t
AudioFormatConverter::Read(void* buffer, int64 pos, int64 frames) AudioFormatConverter::Read(void* buffer, int64 pos, int64 frames)
{ {
@@ -1,25 +1,28 @@
/* /*
* Copyright © 2000-2006 Ingo Weinhold <[email protected]> * Copyright 2000-2006 Ingo Weinhold <[email protected]>
* Copyright © 2008 Stephan Aßmus <[email protected]> * Copyright 2008 Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT licensce. * 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) /*! This AudioReader just converts the source sample format (and byte order)
into another one, e.g. LE short -> BE float. Frame rate and channel into another one, e.g. LE short -> BE float. Frame rate and channel
count remain unchanged. count remain unchanged.
*/ */
#ifndef AUDIO_FORMAT_CONVERTER_H
#define AUDIO_FORMAT_CONVERTER_H
#include "AudioReader.h" #include "AudioReader.h"
class AudioFormatConverter : public AudioReader { class AudioFormatConverter : public AudioReader {
public: public:
AudioFormatConverter(AudioReader* source, AudioFormatConverter(AudioReader* source,
uint32 format, uint32 byte_order); uint32 format, uint32 byte_order);
virtual ~AudioFormatConverter(); virtual ~AudioFormatConverter();
virtual bigtime_t InitialLatency() const;
virtual status_t Read(void* buffer, int64 pos, int64 frames); virtual status_t Read(void* buffer, int64 pos, int64 frames);
virtual status_t InitCheck() const; virtual status_t InitCheck() const;
@@ -37,13 +37,13 @@
// debugging // debugging
//#define TRACE_AUDIO_PRODUCER //#define TRACE_AUDIO_PRODUCER
#ifdef TRACE_AUDIO_PRODUCER #ifdef TRACE_AUDIO_PRODUCER
# define TRACE(x...) printf(x) # define TRACE(x...) printf(x)
# define TRACE_BUFFER(x...) # define TRACE_BUFFER(x...)
# define ERROR(x...) fprintf(stderr, x) # define ERROR(x...) fprintf(stderr, x)
#else #else
# define TRACE(x...) # define TRACE(x...)
# define TRACE_BUFFER(x...) # define TRACE_BUFFER(x...)
# define ERROR(x...) fprintf(stderr, x) # define ERROR(x...) fprintf(stderr, x)
#endif #endif
@@ -85,24 +85,63 @@ init_media_file(media_format format, BMediaTrack** _track)
#endif // DEBUG_TO_FILE #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, AudioProducer::AudioProducer(const char* name, AudioSupplier* supplier,
bool lowLatency) bool lowLatency)
: BMediaNode(name), :
BBufferProducer(B_MEDIA_RAW_AUDIO), BMediaNode(name),
BMediaEventLooper(), BBufferProducer(B_MEDIA_RAW_AUDIO),
BMediaEventLooper(),
fBufferGroup(NULL), fBufferGroup(NULL),
fLatency(0), fLatency(0),
fInternalLatency(0), fInternalLatency(0),
fLowLatency(lowLatency), fLastLateNotice(0),
fOutputEnabled(true), fNextScheduledBuffer(0),
fFramesSent(0), fLowLatency(lowLatency),
fStartTime(0), fOutputEnabled(true),
fSupplier(supplier), fFramesSent(0),
fStartTime(0),
fSupplier(supplier),
fPeakListener(NULL) fPeakListener(NULL)
{ {
TRACE("%p->AudioProducer::AudioProducer(%s, %p, %d)\n", this, name, TRACE("%p->AudioProducer::AudioProducer(%s, %p, %d)\n", this, name,
supplier, lowLatency); supplier, lowLatency);
@@ -135,9 +174,11 @@ AudioProducer::AudioProducer(const char* name, AudioSupplier* supplier,
// we're not connected yet // we're not connected yet
fOutput.destination = media_destination::null; fOutput.destination = media_destination::null;
fOutput.format = fPreferredFormat; fOutput.format = fPreferredFormat;
// init the audio supplier // init the audio supplier
if (fSupplier) { if (fSupplier != NULL) {
fSupplier->SetAudioProducer(this); 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 void
AudioProducer::Connect(status_t error, const media_source& source, AudioProducer::Connect(status_t error, const media_source& source,
const media_destination& destination, const media_format& format, 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 // If we're late, we need to catch up. Respond in a manner appropriate
// to our current run mode. // to our current run mode.
if (what == fOutput.source) { 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) { if (RunMode() == B_RECORDING) {
// ... // ...
} else if (RunMode() == B_INCREASE_LATENCY) { } 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"); TRACE("AudioProducer::HandleEvent(B_START)\n");
if (RunState() != B_STARTED) { if (RunState() != B_STARTED) {
fFramesSent = 0; fFramesSent = 0;
fStartTime = event->event_time; fStartTime = event->event_time + fSupplier->InitialLatency();
printf("B_START: start time: %lld\n", fStartTime); printf("B_START: start time: %lld\n", fStartTime);
media_timed_event firstBufferEvent(fStartTime, media_timed_event firstBufferEvent(
fStartTime - fSupplier->InitialLatency(),
BTimedEventQueue::B_HANDLE_BUFFER); BTimedEventQueue::B_HANDLE_BUFFER);
EventQueue()->AddEvent(firstBufferEvent); EventQueue()->AddEvent(firstBufferEvent);
} }
@@ -607,7 +621,7 @@ printf("B_START: start time: %lld\n", fStartTime);
case BTimedEventQueue::B_STOP: case BTimedEventQueue::B_STOP:
TRACE("AudioProducer::HandleEvent(B_STOP)\n"); TRACE("AudioProducer::HandleEvent(B_STOP)\n");
EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true,
BTimedEventQueue::B_HANDLE_BUFFER); BTimedEventQueue::B_HANDLE_BUFFER);
TRACE("AudioProducer::HandleEvent(B_STOP) done\n"); TRACE("AudioProducer::HandleEvent(B_STOP) done\n");
break; break;
@@ -633,10 +647,10 @@ printf("B_START: start time: %lld\n", fStartTime);
/ (sampleSize * fOutput.format.u.raw_audio.channel_count); / (sampleSize * fOutput.format.u.raw_audio.channel_count);
fFramesSent += nFrames; fFramesSent += nFrames;
bigtime_t nextEvent = fStartTime fNextScheduledBuffer = fStartTime
+ bigtime_t(double(fFramesSent) * 1000000.0 + bigtime_t(double(fFramesSent) * 1000000.0
/ double(fOutput.format.u.raw_audio.frame_rate)); / double(fOutput.format.u.raw_audio.frame_rate));
media_timed_event nextBufferEvent(nextEvent, media_timed_event nextBufferEvent(fNextScheduledBuffer,
BTimedEventQueue::B_HANDLE_BUFFER); BTimedEventQueue::B_HANDLE_BUFFER);
EventQueue()->AddEvent(nextBufferEvent); EventQueue()->AddEvent(nextBufferEvent);
} else { } else {
@@ -663,7 +677,8 @@ AudioProducer::ChangeFormat(media_format* format)
{ {
TRACE("AudioProducer::ChangeFormat()\n"); 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); status_t ret = _SpecializeFormat(format);
if (ret != B_OK) { if (ret != B_OK) {
@@ -677,7 +692,8 @@ AudioProducer::ChangeFormat(media_format* format)
return ret; return ret;
} }
ret = BBufferProducer::ChangeFormat(fOutput.source, fOutput.destination, format); ret = BBufferProducer::ChangeFormat(fOutput.source, fOutput.destination,
format);
if (ret != B_OK) { if (ret != B_OK) {
TRACE(" ChangeFormat(): %s\n", strerror(ret)); TRACE(" ChangeFormat(): %s\n", strerror(ret));
return ret; return ret;
@@ -707,20 +723,20 @@ AudioProducer::_SpecializeFormat(media_format* format)
} }
if (format->u.raw_audio.channel_count 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; format->u.raw_audio.channel_count = 2;
TRACE(" -> adjusting channel count, it was wildcard\n"); TRACE(" -> adjusting channel count, it was wildcard\n");
} }
if (format->u.raw_audio.frame_rate 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; format->u.raw_audio.frame_rate = 44100.0;
TRACE(" -> adjusting frame rate, it was wildcard\n"); TRACE(" -> adjusting frame rate, it was wildcard\n");
} }
// check the buffer size, which may still be wildcarded // check the buffer size, which may still be wildcarded
if (format->u.raw_audio.buffer_size 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 // pick something comfortable to suggest
TRACE(" -> adjusting buffer size, it was wildcard\n"); TRACE(" -> adjusting buffer size, it was wildcard\n");
@@ -734,7 +750,6 @@ AudioProducer::_SpecializeFormat(media_format* format)
if (!fLowLatency) if (!fLowLatency)
format->u.raw_audio.buffer_size *= 3; format->u.raw_audio.buffer_size *= 3;
} }
return B_OK; return B_OK;
@@ -794,9 +809,9 @@ AudioProducer::_FillNextBuffer(bigtime_t eventTime)
// number of sample in the buffer // number of sample in the buffer
// fill in the buffer header // fill in the buffer header
media_header* hdr = buffer->Header(); media_header* header = buffer->Header();
hdr->type = B_MEDIA_RAW_AUDIO; header->type = B_MEDIA_RAW_AUDIO;
hdr->time_source = TimeSource()->ID(); header->time_source = TimeSource()->ID();
buffer->SetSizeUsed(fOutput.format.u.raw_audio.buffer_size); buffer->SetSizeUsed(fOutput.format.u.raw_audio.buffer_size);
bigtime_t performanceTime = bigtime_t(double(fFramesSent) bigtime_t performanceTime = bigtime_t(double(fFramesSent)
@@ -817,9 +832,9 @@ AudioProducer::_FillNextBuffer(bigtime_t eventTime)
// stamp buffer // stamp buffer
if (RunMode() == B_RECORDING) { if (RunMode() == B_RECORDING) {
hdr->start_time = eventTime; header->start_time = eventTime;
} else { } else {
hdr->start_time = fStartTime + performanceTime; header->start_time = fStartTime + performanceTime;
} }
#if DEBUG_TO_FILE #if DEBUG_TO_FILE
@@ -8,10 +8,11 @@
#ifndef AUDIO_PRODUCER_H #ifndef AUDIO_PRODUCER_H
#define AUDIO_PRODUCER_H #define AUDIO_PRODUCER_H
#include <BufferProducer.h> #include <BufferProducer.h>
//#include <Controllable.h>
#include <MediaEventLooper.h> #include <MediaEventLooper.h>
class AudioSupplier; class AudioSupplier;
class BHandler; class BHandler;
@@ -19,6 +20,7 @@ enum {
MSG_PEAK_NOTIFICATION = 'pknt' MSG_PEAK_NOTIFICATION = 'pknt'
}; };
class AudioProducer : public BBufferProducer, public BMediaEventLooper { class AudioProducer : public BBufferProducer, public BMediaEventLooper {
public: public:
AudioProducer(const char* name, AudioProducer(const char* name,
@@ -116,6 +118,8 @@ private:
bool fUsingOurBuffers; bool fUsingOurBuffers;
bigtime_t fLatency; bigtime_t fLatency;
bigtime_t fInternalLatency; bigtime_t fInternalLatency;
bigtime_t fLastLateNotice;
bigtime_t fNextScheduledBuffer;
bool fLowLatency; bool fLowLatency;
media_output fOutput; media_output fOutput;
bool fOutputEnabled; bool fOutputEnabled;
@@ -18,6 +18,7 @@ public:
void SetFormat(const media_format& format); void SetFormat(const media_format& format);
const media_format& Format() const; const media_format& Format() const;
virtual bigtime_t InitialLatency() const = 0;
virtual status_t Read(void* buffer, int64 pos, int64 frames) = 0; virtual status_t Read(void* buffer, int64 pos, int64 frames) = 0;
void SetOutOffset(int64 offset); void SetOutOffset(int64 offset);
@@ -1,7 +1,9 @@
/* /*
* Copyright © 2000-2006 Ingo Weinhold <[email protected]> * Copyright 2000-2006 Ingo Weinhold <[email protected]>
* All rights reserved. Distributed under the terms of the MIT licensce. * All rights reserved. Distributed under the terms of the MIT licensce.
*/ */
#include "AudioResampler.h" #include "AudioResampler.h"
#include <stdio.h> #include <stdio.h>
@@ -11,39 +13,12 @@
//#define TRACE_AUDIO_RESAMPLER //#define TRACE_AUDIO_RESAMPLER
#ifdef TRACE_AUDIO_RESAMPLER #ifdef TRACE_AUDIO_RESAMPLER
# define TRACE(x...) printf(x) # define TRACE(x...) printf(x)
#else #else
# define TRACE(x...) # define TRACE(x...)
#endif #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/. //! Calculates the greatest common divider of /a/ and /b/.
template<typename T> inline template<typename T> inline
T 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 status_t
AudioResampler::Read(void* buffer, int64 pos, int64 frames) AudioResampler::Read(void* buffer, int64 pos, int64 frames)
{ {
@@ -185,7 +199,7 @@ AudioResampler::SetSource(AudioReader* source)
TRACE("AudioResampler::SetSource() - NULL source\n"); TRACE("AudioResampler::SetSource() - NULL source\n");
return; return;
} }
if (source->Format().type != B_MEDIA_RAW_AUDIO) { if (source->Format().type != B_MEDIA_RAW_AUDIO) {
TRACE("AudioResampler::SetSource() - not B_MEDIA_RAW_AUDIO\n"); TRACE("AudioResampler::SetSource() - not B_MEDIA_RAW_AUDIO\n");
return; return;
@@ -197,7 +211,7 @@ AudioResampler::SetSource(AudioReader* source)
TRACE("AudioResampler::SetSource() - not host byte order\n"); TRACE("AudioResampler::SetSource() - not host byte order\n");
return; return;
} }
float frameRate = FrameRate(); float frameRate = FrameRate();
// don't overwrite previous audio frame rate // don't overwrite previous audio frame rate
fSource = source; fSource = source;
@@ -1,7 +1,10 @@
/* /*
* Copyright © 2000-2006 Ingo Weinhold <[email protected]> * Copyright 2000-2006 Ingo Weinhold <[email protected]>
* All rights reserved. Distributed under the terms of the MIT licensce. * 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 /*! 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 sample rate and rescaling the time, e.g. it is possible to convert the
@@ -9,11 +12,10 @@
(time scale = -2). (time scale = -2).
*/ */
#ifndef AUDIO_RESAMPLER_H
#define AUDIO_RESAMPLER_H
#include "AudioReader.h" #include "AudioReader.h"
class AudioResampler : public AudioReader { class AudioResampler : public AudioReader {
public: public:
AudioResampler(); AudioResampler();
@@ -21,6 +23,7 @@ public:
float frameRate, float timeScale = 1.0); float frameRate, float timeScale = 1.0);
virtual ~AudioResampler(); virtual ~AudioResampler();
virtual bigtime_t InitialLatency() const;
virtual status_t Read(void* buffer, int64 pos, int64 frames); virtual status_t Read(void* buffer, int64 pos, int64 frames);
virtual status_t InitCheck() const; virtual status_t InitCheck() const;
@@ -1,6 +1,8 @@
/* Copyright (c) 2000-2008, Ingo Weinhold <[email protected]>, /* Copyright 2000-2008, Ingo Weinhold <[email protected]>,
* All Rights Reserved. Distributed under the terms of the MIT license. * All Rights Reserved. Distributed under the terms of the MIT license.
*/ */
#include "AudioSupplier.h" #include "AudioSupplier.h"
#include "AudioProducer.h" #include "AudioProducer.h"
@@ -26,6 +28,6 @@ AudioSupplier::SetAudioProducer(AudioProducer* producer)
status_t status_t
AudioSupplier::InitCheck() const AudioSupplier::InitCheck() const
{ {
return (fAudioProducer ? B_OK : B_NO_INIT); return fAudioProducer ? B_OK : B_NO_INIT;
} }
@@ -1,11 +1,12 @@
/* Copyright (c) 2000-2008, Ingo Weinhold <[email protected]>, /* Copyright 2000-2008, Ingo Weinhold <[email protected]>,
* All Rights Reserved. Distributed under the terms of the MIT license. * 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 /*! This class is an interface used by the AudioProducer to retreive the
audio data to be played. */ audio data to be played. */
#ifndef AUDIO_SUPPLIER_H
#define AUDIO_SUPPLIER_H
#include <MediaDefs.h> #include <MediaDefs.h>
@@ -14,21 +15,23 @@
class AudioProducer; class AudioProducer;
class AudioSupplier { class AudioSupplier {
public: public:
AudioSupplier(); AudioSupplier();
virtual ~AudioSupplier(); virtual ~AudioSupplier();
virtual void SetAudioProducer(AudioProducer* producer); virtual void SetAudioProducer(AudioProducer* producer);
virtual status_t InitCheck() const;
virtual bigtime_t InitialLatency() const = 0;
virtual status_t GetFrames(void* buffer, int64 frameCount, virtual status_t GetFrames(void* buffer, int64 frameCount,
bigtime_t startTime, bigtime_t startTime,
bigtime_t endTime) = 0; bigtime_t endTime) = 0;
virtual void SetFormat(const media_format& format) = 0; virtual void SetFormat(const media_format& format) = 0;
virtual status_t InitCheck() const; protected:
protected:
AudioProducer* fAudioProducer; AudioProducer* fAudioProducer;
}; };
@@ -1,8 +1,9 @@
/* /*
* Copyright © 2008 Stephan Aßmus <[email protected]> * Copyright 2008 Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT licensce. * All rights reserved. Distributed under the terms of the MIT licensce.
*/ */
#include "AudioVolumeConverter.h" #include "AudioVolumeConverter.h"
#include <stdio.h> #include <stdio.h>
@@ -13,31 +14,12 @@
//#define TRACE_AUDIO_CONVERTER //#define TRACE_AUDIO_CONVERTER
#ifdef TRACE_AUDIO_CONVERTER #ifdef TRACE_AUDIO_CONVERTER
# define TRACE(x...) printf(x) # define TRACE(x...) printf(x)
#else #else
# define TRACE(x...) # define TRACE(x...)
#endif #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<typename SampleType> template<typename SampleType>
static void static void
convert(SampleType* buffer, const int32 samples, const float volume, 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 status_t
AudioVolumeConverter::Read(void* buffer, int64 pos, int64 frames) AudioVolumeConverter::Read(void* buffer, int64 pos, int64 frames)
{ {
@@ -1,23 +1,26 @@
/* /*
* Copyright © 2008 Stephan Aßmus <[email protected]> * Copyright 2008 Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT licensce. * 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 /*! This AudioReader just filters the volume. It depends on floating point
* audio format. * audio format.
*/ */
#ifndef AUDIO_VOLUME_CONVERTER_H
#define AUDIO_VOLUME_CONVERTER_H
#include "AudioReader.h" #include "AudioReader.h"
class AudioVolumeConverter : public AudioReader { class AudioVolumeConverter : public AudioReader {
public: public:
AudioVolumeConverter(AudioReader* source, AudioVolumeConverter(AudioReader* source,
float volume = 1.0); float volume = 1.0);
virtual ~AudioVolumeConverter(); virtual ~AudioVolumeConverter();
virtual bigtime_t InitialLatency() const;
virtual status_t Read(void* buffer, int64 pos, int64 frames); virtual status_t Read(void* buffer, int64 pos, int64 frames);
virtual status_t InitCheck() const; virtual status_t InitCheck() const;
@@ -115,7 +115,14 @@ MediaTrackAudioSupplier::Duration() const
// #pragma mark - AudioReader // #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 status_t
MediaTrackAudioSupplier::Read(void* buffer, int64 pos, int64 frames) 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
// Reads /frames/ frames from /position/ into /buffer/. The frames are not read from the cache, but read frames are cached, if possible.
// read from the cache, but read frames are cached, if possible. New cache buffers are stamped with the supplied time.
// New cache buffers are stamped with the supplied time. If an error occurs, the untouched part of the buffer is set to 0.
// If an error occurs, the untouched part of the buffer is set to 0. */
status_t status_t
MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position, MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position,
int64 frames, bigtime_t time) int64 frames, bigtime_t time)
{ {
TRACE("_ReadUncachedFrames()\n"); TRACE("_ReadUncachedFrames()\n");
status_t error = B_OK; status_t error = B_OK;
@@ -1,21 +1,24 @@
/* /*
* Copyright © 2000-2004 Ingo Weinhold <[email protected]> * Copyright 2000-2004 Ingo Weinhold <[email protected]>
* Copyright © 2006-2008 Stephan Aßmus <[email protected]> * Copyright 2006-2008 Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef MEDIA_TRACK_AUDIO_SUPPLIER_H #ifndef MEDIA_TRACK_AUDIO_SUPPLIER_H
#define MEDIA_TRACK_AUDIO_SUPPLIER_H #define MEDIA_TRACK_AUDIO_SUPPLIER_H
#include <List.h> #include <List.h>
#include "AudioTrackSupplier.h" #include "AudioTrackSupplier.h"
class BMediaTrack; class BMediaTrack;
struct media_codec_info; struct media_codec_info;
struct media_format; struct media_format;
class MediaTrackAudioSupplier : public AudioTrackSupplier { class MediaTrackAudioSupplier : public AudioTrackSupplier {
public: public:
MediaTrackAudioSupplier(BMediaTrack* track, MediaTrackAudioSupplier(BMediaTrack* track,
int32 trackIndex); int32 trackIndex);
virtual ~MediaTrackAudioSupplier(); virtual ~MediaTrackAudioSupplier();
@@ -27,6 +30,7 @@ class MediaTrackAudioSupplier : public AudioTrackSupplier {
// AudioReader interface // AudioReader interface
// (needed to reuse the class as AudioResampler input) // (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 Read(void* buffer, int64 pos, int64 frames);
virtual status_t InitCheck() const; virtual status_t InitCheck() const;
@@ -34,7 +38,7 @@ class MediaTrackAudioSupplier : public AudioTrackSupplier {
virtual int32 TrackIndex() const virtual int32 TrackIndex() const
{ return fTrackIndex; } { return fTrackIndex; }
private: private:
struct Buffer; struct Buffer;
void _InitFromTrack(); void _InitFromTrack();
@@ -1,7 +1,9 @@
/* /*
* Copyright © 2008 Stephan Aßmus <[email protected]> * Copyright 2008 Stephan Aßmus <[email protected]>
* All Rights Reserved. Distributed under the terms of the MIT license. * All Rights Reserved. Distributed under the terms of the MIT license.
*/ */
#include "ProxyAudioSupplier.h" #include "ProxyAudioSupplier.h"
#include <algorithm> #include <algorithm>
@@ -33,8 +35,9 @@ using std::swap;
struct PlayingInterval { struct PlayingInterval {
PlayingInterval(bigtime_t startTime, bigtime_t endTime) 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) ProxyAudioSupplier::ProxyAudioSupplier(PlaybackManager* playbackManager)
: fSupplierLock("audio supplier lock") :
fSupplierLock("audio supplier lock"),
, fPlaybackManager(playbackManager) fPlaybackManager(playbackManager),
, fVideoFrameRate(25.0) fVideoFrameRate(25.0),
, fVolume(1.0) fVolume(1.0),
, fSupplier(NULL) fSupplier(NULL),
, fAdapter(NULL) fAdapter(NULL),
, fVolumeConverter(NULL) fVolumeConverter(NULL),
, fAudioResampler() fAudioResampler()
{ {
TRACE("ProxyAudioSupplier()\n"); 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 status_t
ProxyAudioSupplier::GetFrames(void* buffer, int64 frameCount, ProxyAudioSupplier::GetFrames(void* buffer, int64 frameCount,
bigtime_t startTime, bigtime_t endTime) bigtime_t startTime, bigtime_t endTime)
@@ -100,7 +116,7 @@ ProxyAudioSupplier::GetFrames(void* buffer, int64 frameCount,
ERROR("GetFrames() - zero duration audio interval! start " ERROR("GetFrames() - zero duration audio interval! start "
"time: %lld\n", intervalStartTime); "time: %lld\n", intervalStartTime);
break; break;
} }
if (!playingIntervals.AddItem(interval)) { if (!playingIntervals.AddItem(interval)) {
delete interval; delete interval;
error = B_NO_MEMORY; error = B_NO_MEMORY;
@@ -182,7 +198,7 @@ ProxyAudioSupplier::SetFormat(const media_format& format)
{ {
//printf("ProxyAudioSupplier::SetFormat()\n"); //printf("ProxyAudioSupplier::SetFormat()\n");
#ifdef TRACE_PROXY_AUDIO_SUPPLIER #ifdef TRACE_PROXY_AUDIO_SUPPLIER
char string[256]; char string[256];
string_for_format(format, string, 256); string_for_format(format, string, 256);
TRACE("SetFormat(%s)\n", string); TRACE("SetFormat(%s)\n", string);
#endif #endif
@@ -258,6 +274,7 @@ ProxyAudioSupplier::Volume()
// #pragma mark - audio/video/frame/time conversion // #pragma mark - audio/video/frame/time conversion
int64 int64
ProxyAudioSupplier::_AudioFrameForVideoFrame(int64 frame) const ProxyAudioSupplier::_AudioFrameForVideoFrame(int64 frame) const
{ {
@@ -1,10 +1,11 @@
/* /*
* Copyright © 2008 Stephan Aßmus <[email protected]> * Copyright 2008 Stephan Aßmus <[email protected]>
* All Rights Reserved. Distributed under the terms of the MIT license. * All Rights Reserved. Distributed under the terms of the MIT license.
*/ */
#ifndef PROXY_AUDIO_SUPPLIER_H #ifndef PROXY_AUDIO_SUPPLIER_H
#define PROXY_AUDIO_SUPPLIER_H #define PROXY_AUDIO_SUPPLIER_H
#include <Locker.h> #include <Locker.h>
#include "AudioResampler.h" #include "AudioResampler.h"
@@ -26,6 +27,7 @@ public:
virtual status_t GetFrames(void* buffer, int64 frameCount, virtual status_t GetFrames(void* buffer, int64 frameCount,
bigtime_t startTime, bigtime_t endTime); bigtime_t startTime, bigtime_t endTime);
virtual bigtime_t InitialLatency() const;
virtual void SetFormat(const media_format& format); virtual void SetFormat(const media_format& format);
virtual const media_format& Format() const; virtual const media_format& Format() const;
@@ -49,16 +51,16 @@ private:
void* _SkipFrames(void* buffer, int64 frames) const; void* _SkipFrames(void* buffer, int64 frames) const;
private: private:
BLocker fSupplierLock; mutable BLocker fSupplierLock;
PlaybackManager* fPlaybackManager; PlaybackManager* fPlaybackManager;
float fVideoFrameRate; float fVideoFrameRate;
float fVolume; float fVolume;
AudioTrackSupplier* fSupplier; AudioTrackSupplier* fSupplier;
AudioReader* fAdapter; AudioReader* fAdapter;
AudioVolumeConverter* fVolumeConverter; AudioVolumeConverter* fVolumeConverter;
AudioResampler fAudioResampler; AudioResampler fAudioResampler;
}; };