* 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:
@@ -77,6 +77,13 @@ AudioAdapter::~AudioAdapter()
|
||||
}
|
||||
|
||||
|
||||
bigtime_t
|
||||
AudioAdapter::InitialLatency() const
|
||||
{
|
||||
return fSource->InitialLatency();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
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.
|
||||
*/
|
||||
#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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
|
||||
#include "AudioChannelConverter.h"
|
||||
|
||||
#include <new>
|
||||
@@ -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<typename Type, typename BigType>
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
#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;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/*
|
||||
* Copyright © 2000-2006 Ingo Weinhold <[email protected]>
|
||||
* Copyright © 2008 Stephan Aßmus <[email protected]>
|
||||
* Copyright 2000-2006 Ingo Weinhold <[email protected]>
|
||||
* Copyright 2008 Stephan Aßmus <[email protected]>
|
||||
* All rights reserved. Distributed under the terms of the MIT licensce.
|
||||
*/
|
||||
|
||||
|
||||
#include "AudioFormatConverter.h"
|
||||
|
||||
#include <ByteOrder.h>
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
/*
|
||||
* Copyright © 2000-2006 Ingo Weinhold <[email protected]>
|
||||
* Copyright © 2008 Stephan Aßmus <[email protected]>
|
||||
* Copyright 2000-2006 Ingo Weinhold <[email protected]>
|
||||
* Copyright 2008 Stephan Aßmus <[email protected]>
|
||||
* 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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
#ifndef AUDIO_PRODUCER_H
|
||||
#define AUDIO_PRODUCER_H
|
||||
|
||||
|
||||
#include <BufferProducer.h>
|
||||
//#include <Controllable.h>
|
||||
#include <MediaEventLooper.h>
|
||||
|
||||
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/*
|
||||
* Copyright © 2000-2006 Ingo Weinhold <ingo_weinhold@gmx.de>
|
||||
* Copyright 2000-2006 Ingo Weinhold <ingo_weinhold@gmx.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT licensce.
|
||||
*/
|
||||
|
||||
|
||||
#include "AudioResampler.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -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<typename T> 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;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/*
|
||||
* Copyright © 2000-2006 Ingo Weinhold <ingo_weinhold@gmx.de>
|
||||
* Copyright 2000-2006 Ingo Weinhold <ingo_weinhold@gmx.de>
|
||||
* 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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
#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 <MediaDefs.h>
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/*
|
||||
* Copyright © 2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* Copyright 2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT licensce.
|
||||
*/
|
||||
|
||||
|
||||
#include "AudioVolumeConverter.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -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<typename SampleType>
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
/*
|
||||
* Copyright © 2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* Copyright 2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
/*
|
||||
* Copyright © 2000-2004 Ingo Weinhold <ingo_weinhold@gmx.de>
|
||||
* Copyright © 2006-2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* Copyright 2000-2004 Ingo Weinhold <ingo_weinhold@gmx.de>
|
||||
* Copyright 2006-2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef MEDIA_TRACK_AUDIO_SUPPLIER_H
|
||||
#define MEDIA_TRACK_AUDIO_SUPPLIER_H
|
||||
|
||||
|
||||
#include <List.h>
|
||||
|
||||
#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();
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/*
|
||||
* Copyright © 2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
/*
|
||||
* Copyright 2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* All Rights Reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
|
||||
#include "ProxyAudioSupplier.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/*
|
||||
* Copyright © 2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* Copyright 2008 Stephan Aßmus <superstippi@gmx.de>
|
||||
* All Rights Reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef PROXY_AUDIO_SUPPLIER_H
|
||||
#define PROXY_AUDIO_SUPPLIER_H
|
||||
|
||||
|
||||
#include <Locker.h>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user