large patch by Bek (HOST team):

* style improvements, header reformatting, small refactoring and adding
  of missing copyrights

(to Marcus: this is not the original patch, it has already been revised two
times by myself and I thought it was very nice now)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22426 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2007-10-03 21:19:17 +00:00
parent 88d9b383f5
commit bf7ab50d4c
15 changed files with 670 additions and 675 deletions
@@ -1,26 +1,27 @@
/* AudioMixer /*
* * Copyright 2002 David Shipman,
* First implementation by David Shipman, 2002 * Copyright 2003-2007 Marcus Overhagen
* Rewritten by Marcus Overhagen, 2003 * Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/ */
#include <RealtimeAlloc.h>
#include <Buffer.h>
#include <TimeSource.h>
#include <ParameterWeb.h>
#include <MediaRoster.h>
#include <FindDirectory.h>
#include <Path.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "AudioMixer.h" #include "AudioMixer.h"
#include "MixerCore.h" #include "MixerCore.h"
#include "MixerInput.h" #include "MixerInput.h"
#include "MixerOutput.h" #include "MixerOutput.h"
#include "MixerUtils.h" #include "MixerUtils.h"
#include <Buffer.h>
#include <FindDirectory.h>
#include <math.h>
#include <MediaRoster.h>
#include <ParameterWeb.h>
#include <Path.h>
#include <RealtimeAlloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <TimeSource.h>
#define VERSION_STRING "0.4" #define VERSION_STRING "0.4"
#define BUILD_STRING __DATE__ " " __TIME__ #define BUILD_STRING __DATE__ " " __TIME__
@@ -34,7 +35,9 @@
#define USE_MEDIA_FORMAT_WORKAROUND 1 #define USE_MEDIA_FORMAT_WORKAROUND 1
#if USE_MEDIA_FORMAT_WORKAROUND #if USE_MEDIA_FORMAT_WORKAROUND
static void multi_audio_format_specialize(media_multi_audio_format *format, const media_multi_audio_format *other); static void
multi_audio_format_specialize(media_multi_audio_format *format,
const media_multi_audio_format *other);
#endif #endif
#define FORMAT_USER_DATA_TYPE 0x7294a8f3 #define FORMAT_USER_DATA_TYPE 0x7294a8f3
@@ -238,9 +241,11 @@ AudioMixer::BufferReceived(BBuffer *buffer)
//PRINT(4, "buffer received at %12Ld, should arrive at %12Ld, delta %12Ld\n", TimeSource()->Now(), buffer->Header()->start_time, TimeSource()->Now() - buffer->Header()->start_time); //PRINT(4, "buffer received at %12Ld, should arrive at %12Ld, delta %12Ld\n", TimeSource()->Now(), buffer->Header()->start_time, TimeSource()->Now() - buffer->Header()->start_time);
// HandleInputBuffer(buffer, 0); // Note: The following code is outcommented on purpose
// buffer->Recycle(); // and is about to be modified at a later point
// return; // HandleInputBuffer(buffer, 0);
// buffer->Recycle();
// return;
// to receive the buffer at the right time, // to receive the buffer at the right time,
@@ -256,7 +261,9 @@ AudioMixer::BufferReceived(BBuffer *buffer)
void void
AudioMixer::HandleInputBuffer(BBuffer *buffer, bigtime_t lateness) AudioMixer::HandleInputBuffer(BBuffer *buffer, bigtime_t lateness)
{ {
/* // Note: The following code is outcommented on purpose
// and is about to be modified at a later point
/*
if (lateness > 5000) { if (lateness > 5000) {
printf("Received buffer with way to high lateness %Ld\n", lateness); printf("Received buffer with way to high lateness %Ld\n", lateness);
if (RunMode() != B_DROP_DATA) { if (RunMode() != B_DROP_DATA) {
@@ -267,20 +274,22 @@ AudioMixer::HandleInputBuffer(BBuffer *buffer, bigtime_t lateness)
return; return;
} }
} }
*/ */
// printf("Received buffer with lateness %Ld\n", lateness); // printf("Received buffer with lateness %Ld\n", lateness);
fCore->Lock(); fCore->Lock();
fCore->BufferReceived(buffer, lateness); fCore->BufferReceived(buffer, lateness);
fCore->Unlock(); fCore->Unlock();
/* // Note: The following code is outcommented on purpose
// and is about to be modified at a later point
/*
if ((B_OFFLINE == RunMode()) && (B_DATA_AVAILABLE == channel->fProducerDataStatus)) if ((B_OFFLINE == RunMode()) && (B_DATA_AVAILABLE == channel->fProducerDataStatus))
{ {
RequestAdditionalBuffer(channel->fInput.source, buffer); RequestAdditionalBuffer(channel->fInput.source, buffer);
} }
*/ */
} }
void void
@@ -316,10 +325,11 @@ AudioMixer::GetLatencyFor(const media_destination &for_whom,
*out_latency = EventLatency(); *out_latency = EventLatency();
*out_timesource = TimeSource()->ID(); *out_timesource = TimeSource()->ID();
printf("AudioMixer::GetLatencyFor %Ld, timesource is %ld\n", *out_latency, *out_timesource); printf("AudioMixer::GetLatencyFor %Ld, timesource is %ld\n",
*out_latency,
*out_timesource);
return B_OK; return B_OK;
} }
status_t status_t
@@ -331,13 +341,16 @@ AudioMixer::Connected(const media_source &producer, const media_destination &whe
// workaround for a crashing bug in RealPlayer. to be proper, RealPlayer's // workaround for a crashing bug in RealPlayer. to be proper, RealPlayer's
// BBufferProducer::PrepareToConnect() should have removed all wildcards. // BBufferProducer::PrepareToConnect() should have removed all wildcards.
if (out_input->format.u.raw_audio.frame_rate == 0) { if (out_input->format.u.raw_audio.frame_rate == 0) {
fprintf(stderr, "Audio Mixer Warning: Producer (port %ld, id %ld) connected with frame_rate=0\n", producer.port, producer.id); fprintf(stderr, "Audio Mixer Warning: "
"Producer (port %ld, id %ld) connected with frame_rate=0\n",
producer.port,
producer.id);
MixerOutput *output = fCore->Output(); MixerOutput *output = fCore->Output();
float frame_rate = output ? output->MediaOutput().format.u.raw_audio.frame_rate : 44100.0f; float frame_rate = output ? output->MediaOutput().format.u.raw_audio.frame_rate : 44100.0f;
out_input->format.u.raw_audio.frame_rate = frame_rate; out_input->format.u.raw_audio.frame_rate = frame_rate;
} }
// a BBufferProducer is connection to our BBufferConsumer // a BBufferProducer is connecting to our BBufferConsumer
// incoming connections should always have an incoming ID=0, // incoming connections should always have an incoming ID=0,
// and the port number must match our ControlPort() // and the port number must match our ControlPort()
@@ -390,7 +403,6 @@ AudioMixer::Disconnected(const media_source &producer, const media_destination &
} }
fCore->Unlock(); fCore->Unlock();
UpdateParameterWeb(); UpdateParameterWeb();
} }
@@ -467,6 +479,11 @@ AudioMixer::FormatProposal(const media_source &output, media_format *ioFormat)
return B_OK; return B_OK;
} }
// If the format isn't good, put a good format into *io_format and return error
// If format has wildcard, specialize to what you can do (and change).
// If you can change the format, return OK.
// The request comes from your destination sychronously, so you cannot ask it
// whether it likes it -- you should assume it will since it asked.
status_t status_t
AudioMixer::FormatChangeRequested(const media_source &source, const media_destination &destination, AudioMixer::FormatChangeRequested(const media_source &source, const media_destination &destination,
media_format *io_format, int32 *_deprecated_) media_format *io_format, int32 *_deprecated_)
@@ -498,8 +515,6 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin
if (destination.port == output->MediaOutput().destination.port && destination.id == output->MediaOutput().destination.id + 1) { if (destination.port == output->MediaOutput().destination.port && destination.id == output->MediaOutput().destination.id + 1) {
ERROR("AudioMixer::FormatChangeRequested: this might be the broken R5 multi audio add-on\n"); ERROR("AudioMixer::FormatChangeRequested: this might be the broken R5 multi audio add-on\n");
goto err; goto err;
// fCore->Unlock();
// return B_OK;
} else { } else {
goto err; goto err;
} }
@@ -583,21 +598,23 @@ AudioMixer::GetNextOutput(int32 *cookie, media_output *out_output)
status_t status_t
AudioMixer::DisposeOutputCookie(int32 cookie) AudioMixer::DisposeOutputCookie(int32 cookie)
{ {
// nothin to do // nothing to do
return B_OK; return B_OK;
} }
status_t status_t
AudioMixer::SetBufferGroup(const media_source &for_source, BBufferGroup *newGroup) AudioMixer::SetBufferGroup(const media_source &for_source, BBufferGroup *newGroup)
{ {
printf("#############################AudioMixer::SetBufferGroup\n"); PRINT("AudioMixer::SetBufferGroup\n");
// the downstream consumer (soundcard) node asks us to use another // the downstream consumer (soundcard) node asks us to use another
// BBufferGroup (might be NULL). We only have one output (id 0) // BBufferGroup (might be NULL). We only have one output (id 0)
if (for_source.port != ControlPort() || for_source.id != 0) if (for_source.port != ControlPort() || for_source.id != 0)
return B_MEDIA_BAD_SOURCE; return B_MEDIA_BAD_SOURCE;
if (newGroup == fBufferGroup) // we're already using this buffergroup if (newGroup == fBufferGroup) {
// we're already using this buffergroup
return B_OK; return B_OK;
}
fCore->Lock(); fCore->Lock();
if (!newGroup) if (!newGroup)
@@ -654,11 +671,13 @@ AudioMixer::LatencyChanged(const media_source & source, const media_destination
} }
status_t status_t
AudioMixer::PrepareToConnect(const media_source &what, const media_destination &where, AudioMixer::PrepareToConnect(const media_source &what,
media_format *format, media_source *out_source, char *out_name) const media_destination &where,
media_format *format,
media_source *out_source,
char *out_name)
{ {
TRACE("AudioMixer::PrepareToConnect\n"); TRACE("AudioMixer::PrepareToConnect\n");
// PrepareToConnect() is the second stage of format negotiations that happens // PrepareToConnect() is the second stage of format negotiations that happens
// inside BMediaRoster::Connect(). At this point, the consumer's AcceptFormat() // inside BMediaRoster::Connect(). At this point, the consumer's AcceptFormat()
// method has been called, and that node has potentially changed the proposed // method has been called, and that node has potentially changed the proposed
@@ -753,14 +772,14 @@ AudioMixer::PrepareToConnect(const media_source &what, const media_destination &
fCore->AddOutput(output); fCore->AddOutput(output);
fCore->Unlock(); fCore->Unlock();
return B_OK; return B_OK;
} }
void void
AudioMixer::Connect(status_t error, const media_source &source, const media_destination &dest, AudioMixer::Connect(status_t error, const media_source &source,
const media_format &format, char *io_name) const media_destination &dest,
const media_format &format,
char *io_name)
{ {
TRACE("AudioMixer::Connect\n"); TRACE("AudioMixer::Connect\n");
@@ -837,17 +856,13 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest
fCore->Settings()->LoadConnectionSettings(fCore->Output()); fCore->Settings()->LoadConnectionSettings(fCore->Output());
fCore->Unlock(); fCore->Unlock();
UpdateParameterWeb(); UpdateParameterWeb();
} }
void void
AudioMixer::Disconnect(const media_source &what, const media_destination &where) AudioMixer::Disconnect(const media_source &what, const media_destination &where)
{ {
TRACE("AudioMixer::Disconnect\n"); TRACE("AudioMixer::Disconnect\n");
fCore->Lock(); fCore->Lock();
// Make sure that our connection is the one being disconnected // Make sure that our connection is the one being disconnected
@@ -858,9 +873,8 @@ AudioMixer::Disconnect(const media_source &what, const media_destination &where)
return; return;
} }
/* Switch our prefered format back to default // Switch our prefered format back to default
* frame rate and channel count. // frame rate and channel count.
*/
fDefaultFormat.u.raw_audio.frame_rate = 96000; fDefaultFormat.u.raw_audio.frame_rate = 96000;
fDefaultFormat.u.raw_audio.channel_count = 2; fDefaultFormat.u.raw_audio.channel_count = 2;
@@ -875,7 +889,6 @@ AudioMixer::Disconnect(const media_source &what, const media_destination &where)
fCore->SetOutputBufferGroup(0); fCore->SetOutputBufferGroup(0);
fCore->Unlock(); fCore->Unlock();
UpdateParameterWeb(); UpdateParameterWeb();
} }
@@ -887,8 +900,9 @@ AudioMixer::LateNoticeReceived(const media_source &what, bigtime_t how_much, big
// is the only runmode in which we can do anything about this // is the only runmode in which we can do anything about this
ERROR("AudioMixer::LateNoticeReceived, %Ld too late at %Ld\n", how_much, performance_time); ERROR("AudioMixer::LateNoticeReceived, %Ld too late at %Ld\n", how_much, performance_time);
// Note: The following code is outcommented on purpose
/* // and is about to be modified at a later point
/*
if (what == fOutput.source) { if (what == fOutput.source) {
if (RunMode() == B_INCREASE_LATENCY) { if (RunMode() == B_INCREASE_LATENCY) {
fInternalLatency += how_much; fInternalLatency += how_much;
@@ -902,7 +916,7 @@ AudioMixer::LateNoticeReceived(const media_source &what, bigtime_t how_much, big
PublishEventLatencyChange(); PublishEventLatencyChange();
} }
} }
*/ */
} }
@@ -1016,7 +1030,8 @@ AudioMixer::PublishEventLatencyChange()
BBufferGroup * BBufferGroup *
AudioMixer::CreateBufferGroup() AudioMixer::CreateBufferGroup()
{ {
// allocate enough buffers to span our downstream latency (plus one for rounding up), plus one extra // allocate enough buffers to span our downstream latency
// (plus one for rounding up), plus one extra
int32 count = int32(fDownstreamLatency / BufferDuration()) + 2; int32 count = int32(fDownstreamLatency / BufferDuration()) + 2;
TRACE("AudioMixer::CreateBufferGroup: fDownstreamLatency %Ld, BufferDuration %Ld, buffer count = %ld\n", fDownstreamLatency, BufferDuration(), count); TRACE("AudioMixer::CreateBufferGroup: fDownstreamLatency %Ld, BufferDuration %Ld, buffer count = %ld\n", fDownstreamLatency, BufferDuration(), count);
@@ -1672,11 +1687,14 @@ AudioMixer::UpdateParameterWeb()
dp = group->MakeDiscreteParameter(PARAM_ETC(70), B_MEDIA_RAW_AUDIO, "Resampling algorithm", B_INPUT_MUX); dp = group->MakeDiscreteParameter(PARAM_ETC(70), B_MEDIA_RAW_AUDIO, "Resampling algorithm", B_INPUT_MUX);
dp->AddItem(0, "Drop/repeat samples"); dp->AddItem(0, "Drop/repeat samples");
/*
// Note: The following code is outcommented on purpose
// and is about to be modified at a later point
/*
dp->AddItem(1, "Drop/repeat samples (template based)"); dp->AddItem(1, "Drop/repeat samples (template based)");
dp->AddItem(2, "Linear interpolation"); dp->AddItem(2, "Linear interpolation");
dp->AddItem(3, "17th order filtering"); dp->AddItem(3, "17th order filtering");
*/ */
group->MakeDiscreteParameter(PARAM_ETC(80), B_MEDIA_RAW_AUDIO, "Refuse output format changes", B_ENABLE); group->MakeDiscreteParameter(PARAM_ETC(80), B_MEDIA_RAW_AUDIO, "Refuse output format changes", B_ENABLE);
group->MakeDiscreteParameter(PARAM_ETC(90), B_MEDIA_RAW_AUDIO, "Refuse input format changes", B_ENABLE); group->MakeDiscreteParameter(PARAM_ETC(90), B_MEDIA_RAW_AUDIO, "Refuse input format changes", B_ENABLE);
@@ -1691,7 +1709,6 @@ AudioMixer::UpdateParameterWeb()
, B_GENERIC); , B_GENERIC);
fCore->Unlock(); fCore->Unlock();
SetParameterWeb(web); SetParameterWeb(web);
} }
@@ -1,47 +1,34 @@
// AudioMixer.h
/* /*
* Copyright 2002 David Shipman,
By David Shipman, 2002 * Copyright 2003-2007 Marcus Overhagen
* Copyright 2007 Haiku Inc. All rights reserved.
*/ * Distributed under the terms of the MIT License.
*/
#ifndef _AUDIOMIXER_H #ifndef _AUDIOMIXER_H
#define _AUDIOMIXER_H #define _AUDIOMIXER_H
// forward declarations #include <BufferConsumer.h>
#include <BufferGroup.h>
#include <BufferProducer.h>
#include <Controllable.h>
#include <MediaEventLooper.h>
#include <MediaNode.h>
class MixerCore; class MixerCore;
// includes
#include <media/BufferGroup.h>
#include <media/MediaNode.h>
#include <media/BufferConsumer.h>
#include <media/BufferProducer.h>
#include <media/Controllable.h>
#include <media/MediaEventLooper.h>
// ----------------
// AudioMixer class
class AudioMixer : class AudioMixer :
public BBufferConsumer, public BBufferConsumer,
public BBufferProducer, public BBufferProducer,
public BControllable, public BControllable,
public BMediaEventLooper public BMediaEventLooper
{ {
public: public:
AudioMixer(BMediaAddOn *addOn, bool isSystemMixer); AudioMixer(BMediaAddOn *addOn, bool isSystemMixer);
~AudioMixer(); ~AudioMixer();
void DisableNodeStop(); void DisableNodeStop();
// AudioMixer support // AudioMixer support
void ApplySettings(); void ApplySettings();
void PublishEventLatencyChange(); void PublishEventLatencyChange();
@@ -55,142 +42,92 @@ class AudioMixer :
float Gain_to_dB(float gain); float Gain_to_dB(float gain);
// BMediaNode methods // BMediaNode methods
BMediaAddOn * AddOn(int32 *internal_id) const;
BMediaAddOn * AddOn(int32*) const;
// void SetRunMode(run_mode);
// void Preroll();
// status_t RequestCompleted(const media_request_info & info);
void NodeRegistered(); void NodeRegistered();
void Stop(bigtime_t performance_time, bool immediate); void Stop(bigtime_t performance_time, bool immediate);
void SetTimeSource(BTimeSource * time_source); void SetTimeSource(BTimeSource * time_source);
using BBufferProducer::SendBuffer; using BBufferProducer::SendBuffer;
protected: protected:
// BControllable methods // BControllable methods
status_t GetParameterValue(int32 id,
bigtime_t *last_change,
void *value,
size_t *ioSize);
status_t GetParameterValue( int32 id, bigtime_t* last_change, void SetParameterValue(int32 id, bigtime_t when,
void* value, const void *value,
size_t* ioSize);
void SetParameterValue( int32 id, bigtime_t when,
const void* value,
size_t size); size_t size);
// BBufferConsumer methods // BBufferConsumer methods
status_t HandleMessage(int32 message, const void* data,
status_t HandleMessage( int32 message,
const void* data,
size_t size); size_t size);
status_t AcceptFormat(const media_destination &dest,
status_t AcceptFormat( const media_destination &dest, media_format *format); media_format *format);
status_t GetNextInput(int32 *cookie,
status_t GetNextInput( int32 *cookie,
media_input *out_input); media_input *out_input);
void DisposeInputCookie(int32 cookie);
void DisposeInputCookie( int32 cookie); void BufferReceived(BBuffer *buffer);
void ProducerDataStatus(const media_destination &for_whom,
void BufferReceived( BBuffer *buffer);
void ProducerDataStatus( const media_destination &for_whom,
int32 status, int32 status,
bigtime_t at_performance_time); bigtime_t at_performance_time);
status_t GetLatencyFor(const media_destination &for_whom,
status_t GetLatencyFor( const media_destination &for_whom,
bigtime_t *out_latency, bigtime_t *out_latency,
media_node_id *out_timesource); media_node_id *out_timesource);
status_t Connected(const media_source &producer,
status_t Connected( const media_source &producer,
const media_destination &where, const media_destination &where,
const media_format &with_format, const media_format &with_format,
media_input *out_input); media_input *out_input);
void Disconnected(const media_source &producer,
void Disconnected( const media_source &producer,
const media_destination &where); const media_destination &where);
status_t FormatChanged(const media_source &producer,
status_t FormatChanged( const media_source &producer,
const media_destination &consumer, const media_destination &consumer,
int32 change_tag, int32 change_tag,
const media_format &format); const media_format &format);
//
// BBufferProducer methods // BBufferProducer methods
// status_t FormatSuggestionRequested(media_type type,
status_t FormatSuggestionRequested( media_type type,
int32 quality, int32 quality,
media_format *format); media_format *format);
status_t FormatProposal(const media_source &output,
status_t FormatProposal( media_format *format);
const media_source& output,
media_format* format);
//
// /* If the format isn't good, put a good format into *io_format and return error */
// /* If format has wildcard, specialize to what you can do (and change). */
// /* If you can change the format, return OK. */
// /* The request comes from your destination sychronously, so you cannot ask it */
// /* whether it likes it -- you should assume it will since it asked. */
status_t FormatChangeRequested( status_t FormatChangeRequested(
const media_source& source, const media_source& source,
const media_destination& destination, const media_destination &destination,
media_format* io_format, media_format *io_format,
int32* _deprecated_); int32 *_deprecated_);
status_t GetNextOutput(int32 *cookie,media_output *out_output);
status_t GetNextOutput( /* cookie starts as 0 */ status_t DisposeOutputCookie(int32 cookie);
int32* cookie, status_t SetBufferGroup(const media_source &for_source,
media_output* out_output); BBufferGroup *group);
status_t GetLatency(bigtime_t *out_latency);
status_t DisposeOutputCookie( status_t PrepareToConnect(const media_source &what,
int32 cookie); const media_destination &where,
media_format *format,
status_t SetBufferGroup( media_source *out_source,
const media_source& for_source, char *out_name);
BBufferGroup* group); void Connect(status_t error,
const media_source &source,
status_t GetLatency( const media_destination &destination,
bigtime_t* out_latency); const media_format &format,
char *io_name);
status_t PrepareToConnect( void Disconnect(const media_source &what,
const media_source& what, const media_destination &where);
const media_destination& where, void LateNoticeReceived(const media_source &what,
media_format* format,
media_source* out_source,
char* out_name);
void Connect(
status_t error,
const media_source& source,
const media_destination& destination,
const media_format& format,
char* io_name);
void Disconnect(
const media_source& what,
const media_destination& where);
void LateNoticeReceived(
const media_source& what,
bigtime_t how_much, bigtime_t how_much,
bigtime_t performance_time); bigtime_t performance_time);
void EnableOutput(const media_source &what,
void EnableOutput(
const media_source & what,
bool enabled, bool enabled,
int32* _deprecated_); int32 *_deprecated_);
void LatencyChanged(const media_source &source,
void LatencyChanged(const media_source & source, const media_destination &destination,
const media_destination & destination,
bigtime_t new_latency, uint32 flags); bigtime_t new_latency, uint32 flags);
// BMediaEventLooper methods // BMediaEventLooper methods
void HandleEvent(const media_timed_event *event,
void HandleEvent( const media_timed_event *event,
bigtime_t lateness, bigtime_t lateness,
bool realTimeEvent = false); bool realTimeEvent = false);
private: private:
BMediaAddOn *fAddOn; BMediaAddOn *fAddOn;
MixerCore *fCore; MixerCore *fCore;
@@ -201,5 +138,4 @@ class AudioMixer :
bool fDisableStop; bool fDisableStop;
media_format fDefaultFormat; media_format fDefaultFormat;
}; };
#endif #endif
@@ -1,14 +1,14 @@
/* Copyright (C) 2003 Marcus Overhagen /*
* Released under terms of the MIT license. * Copyright 2003-2007 Marcus Overhagen
* * Copyright 2007 Haiku Inc. All rights reserved.
* A simple byte order swapping class for the audio mixer. * Distributed under the terms of the MIT License.
*/ */
#include <MediaDefs.h>
#include <ByteOrder.h>
#include "ByteSwap.h" #include "ByteSwap.h"
#include "MixerDebug.h" #include "MixerDebug.h"
#include <ByteOrder.h>
#include <MediaDefs.h>
static void swap_float(void *buffer, size_t bytecount); static void swap_float(void *buffer, size_t bytecount);
static void swap_int32(void *buffer, size_t bytecount); static void swap_int32(void *buffer, size_t bytecount);
static void swap_int16(void *buffer, size_t bytecount); static void swap_int16(void *buffer, size_t bytecount);
@@ -48,13 +48,15 @@ do_nothing(void *buffer, size_t bytecount)
void void
swap_float(void *buffer, size_t bytecount) swap_float(void *buffer, size_t bytecount)
{ {
swap_data(B_FLOAT_TYPE, buffer, bytecount, B_SWAP_ALWAYS); // XXX should be optimized // XXX Should be optimized
swap_data(B_FLOAT_TYPE, buffer, bytecount, B_SWAP_ALWAYS);
} }
void void
swap_int32(void *buffer, size_t bytecount) swap_int32(void *buffer, size_t bytecount)
{ {
swap_data(B_INT32_TYPE, buffer, bytecount, B_SWAP_ALWAYS); // XXX should be optimized // XXX Should be optimized
swap_data(B_INT32_TYPE, buffer, bytecount, B_SWAP_ALWAYS);
} }
void void
@@ -130,5 +132,4 @@ swap_int16(void *buffer, size_t bytecount)
{ {
swap_data(B_INT16_TYPE, buffer, bytecount, B_SWAP_ALWAYS); swap_data(B_INT16_TYPE, buffer, bytecount, B_SWAP_ALWAYS);
} }
#endif #endif
@@ -1,21 +1,22 @@
/*
* Copyright 2003-2007 Marcus Overhagen
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _BYTE_SWAP_H #ifndef _BYTE_SWAP_H
#define _BYTE_SWAP_H #define _BYTE_SWAP_H
/* Copyright (C) 2003 Marcus Overhagen #include <SupportDefs.h>
* Released under terms of the MIT license.
*
* A simple byte order swapping class for the audio mixer.
*/
class ByteSwap class ByteSwap
{ {
public: public:
ByteSwap(uint32 format); ByteSwap(uint32 format);
~ByteSwap(); ~ByteSwap();
void Swap(void *buffer, size_t bytecount); void Swap(void *buffer, size_t bytecount);
private: private:
void (*fFunc)(void *, size_t); void (*fFunc)(void *, size_t);
}; };
@@ -24,5 +25,4 @@ ByteSwap::Swap(void *buffer, size_t bytecount)
{ {
(*fFunc)(buffer, bytecount); (*fFunc)(buffer, bytecount);
} }
#endif #endif
@@ -1,11 +1,9 @@
// MixerAddOn.cpp /*
// * Copyright 2002 David Shipman,
// David Shipman, 2002 * Copyright 2003-2007 Marcus Overhagen
// Marcus Overhagen, 2003 * Copyright 2007 Haiku Inc. All rights reserved.
// * Distributed under the terms of the MIT License.
// Allows AudioMixer to be used as an addon. */
// The add-on will request to be auto-started.
#include <MediaRoster.h> #include <MediaRoster.h>
#include <MediaNode.h> #include <MediaNode.h>
#include <cstring> #include <cstring>
@@ -19,21 +17,15 @@ extern "C" _EXPORT BMediaAddOn* make_media_addon(image_id image) {
return new AudioMixerAddon(image); return new AudioMixerAddon(image);
} }
// ------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //
AudioMixerAddon::AudioMixerAddon(image_id image) AudioMixerAddon::AudioMixerAddon(image_id image)
: BMediaAddOn(image), : BMediaAddOn(image),
fFormat(new media_format), fFormat(new media_format),
fInfo(new flavor_info) fInfo(new flavor_info)
{ {
// Init media_format
memset(fFormat, 0, sizeof(*fFormat)); memset(fFormat, 0, sizeof(*fFormat));
fFormat->type = B_MEDIA_RAW_AUDIO; fFormat->type = B_MEDIA_RAW_AUDIO;
fFormat->u.raw_audio = media_raw_audio_format::wildcard; fFormat->u.raw_audio = media_raw_audio_format::wildcard;
// Init flavor_info
fInfo->internal_id = 0; fInfo->internal_id = 0;
fInfo->name = "Audio Mixer (Haiku)"; fInfo->name = "Audio Mixer (Haiku)";
fInfo->info = "Haiku Audio Mixer media addon"; fInfo->info = "Haiku Audio Mixer media addon";
@@ -96,13 +88,12 @@ AudioMixerAddon::GetConfigurationFor(BMediaNode* your_node, BMessage* into_messa
bool bool
AudioMixerAddon::WantsAutoStart() AudioMixerAddon::WantsAutoStart()
{ {
// yes, please kick me
return true; return true;
} }
status_t status_t
AudioMixerAddon::AutoStart(int in_index, BMediaNode ** out_node, AudioMixerAddon::AutoStart(int in_index, BMediaNode **out_node,
int32 * out_internal_id, bool * out_has_more) int32 *out_internal_id, bool *out_has_more)
{ {
*out_has_more = false; *out_has_more = false;
@@ -1,49 +1,39 @@
// MixerAddon.h /*
// David Shipman, 2002 * Copyright 2002 David Shipman,
// * Copyright 2003-2007 Marcus Overhagen
// Quick addon header for the Audio Mixer * Copyright 2007 Haiku Inc. All rights reserved.
// * Distributed under the terms of the MIT License.
*/
#ifndef __AudioMixerAddOn_H_ #ifndef _AUDIOMIXER_ADDON_H
#define __AudioMixerAddOn_H_ #define _AUDIOMIXER_ADDON_H
#include <MediaAddOn.h> #include <MediaAddOn.h>
// -------------------------------------------------------- // class AudioMixerAddon : public BMediaAddOn {
public:
class AudioMixerAddon :
public BMediaAddOn {
typedef BMediaAddOn _inherited;
public: // ctor/dtor
virtual ~AudioMixerAddon(); virtual ~AudioMixerAddon();
explicit AudioMixerAddon(image_id image); explicit AudioMixerAddon(image_id image);
public: // BMediaAddOn impl virtual status_t InitCheck(const char** out_failure_text);
virtual status_t InitCheck( virtual int32 CountFlavors();
const char** out_failure_text); virtual status_t GetFlavorAt(int32 n,
virtual int32 CountFlavors();
virtual status_t GetFlavorAt(
int32 n,
const flavor_info ** out_info); const flavor_info ** out_info);
virtual BMediaNode * InstantiateNodeFor( virtual BMediaNode * InstantiateNodeFor(
const flavor_info * info, const flavor_info *info,
BMessage * config, BMessage *config,
status_t * out_error); status_t *out_error);
virtual status_t GetConfigurationFor( virtual status_t GetConfigurationFor(
BMediaNode * your_node, BMediaNode *your_node,
BMessage * into_message); BMessage *into_message);
virtual bool WantsAutoStart(); virtual bool WantsAutoStart();
virtual status_t AutoStart( virtual status_t AutoStart(int in_index,
int in_index, BMediaNode **out_node,
BMediaNode ** out_node, int32 *out_internal_id,
int32 * out_internal_id, bool *out_has_more);
bool * out_has_more);
private: private:
media_format *fFormat; media_format *fFormat;
flavor_info *fInfo; flavor_info *fInfo;
}; };
#endif
#endif /*__AudioMixerAddOn_H_*/
@@ -1,19 +1,27 @@
#include <RealtimeAlloc.h> /*
#include <MediaNode.h> * Copyright 2007 Haiku Inc. All rights reserved.
#include <BufferProducer.h> * Distributed under the terms of the MIT License.
#include <TimeSource.h> *
#include <Buffer.h> * Authors:
#include <BufferGroup.h> * Marcus Overhagen
#include <StopWatch.h> */
#include <string.h> #include "AudioMixer.h"
#include "MixerCore.h" #include "MixerCore.h"
#include "MixerInput.h" #include "MixerInput.h"
#include "MixerOutput.h" #include "MixerOutput.h"
#include "MixerUtils.h" #include "MixerUtils.h"
#include "AudioMixer.h"
#include "Resampler.h" #include "Resampler.h"
#include "RtList.h" #include "RtList.h"
#include <Buffer.h>
#include <BufferGroup.h>
#include <BufferProducer.h>
#include <MediaNode.h>
#include <RealtimeAlloc.h>
#include <StopWatch.h>
#include <TimeSource.h>
#include <string.h>
#define DOUBLE_RATE_MIXING 0 #define DOUBLE_RATE_MIXING 0
#if DEBUG > 1 #if DEBUG > 1
@@ -77,7 +85,6 @@ MixerCore::~MixerCore()
if (fTimeSource) if (fTimeSource)
fTimeSource->Release(); fTimeSource->Release();
// delete resamplers
if (fResampler) { if (fResampler) {
for (int i = 0; i < fMixBufferChannelCount; i++) for (int i = 0; i < fMixBufferChannelCount; i++)
delete fResampler[i]; delete fResampler[i];
@@ -104,7 +111,8 @@ MixerInput *
MixerCore::AddInput(const media_input &input) MixerCore::AddInput(const media_input &input)
{ {
ASSERT_LOCKED(); ASSERT_LOCKED();
MixerInput *in = new MixerInput(this, input, fMixBufferFrameRate, fMixBufferFrameCount); MixerInput *in = new MixerInput(this, input, fMixBufferFrameRate,
fMixBufferFrameCount);
fInputs->AddItem(in); fInputs->AddItem(in);
return in; return in;
} }
@@ -206,7 +214,6 @@ void
MixerCore::OutputFormatChanged(const media_multi_audio_format &format) MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
{ {
ASSERT_LOCKED(); ASSERT_LOCKED();
bool was_started = fStarted; bool was_started = fStarted;
if (was_started) if (was_started)
@@ -247,16 +254,17 @@ MixerCore::ApplyOutputFormat()
fMixBuffer = (float *)rtm_alloc(NULL, sizeof(float) * fMixBufferFrameCount * fMixBufferChannelCount); fMixBuffer = (float *)rtm_alloc(NULL, sizeof(float) * fMixBufferFrameCount * fMixBufferChannelCount);
ASSERT(fMixBuffer); ASSERT(fMixBuffer);
// delete resamplers
if (fResampler) { if (fResampler) {
for (int i = 0; i < fMixBufferChannelCount; i++) for (int i = 0; i < fMixBufferChannelCount; i++)
delete fResampler[i]; delete fResampler[i];
delete [] fResampler; delete [] fResampler;
} }
// create new resamplers
fResampler = new Resampler * [fMixBufferChannelCount]; fResampler = new Resampler * [fMixBufferChannelCount];
for (int i = 0; i < fMixBufferChannelCount; i++) for (int i = 0; i < fMixBufferChannelCount; i++)
fResampler[i] = new Resampler(media_raw_audio_format::B_AUDIO_FLOAT, format.format, format.valid_bits); fResampler[i] = new Resampler(media_raw_audio_format::B_AUDIO_FLOAT,
format.format,
format.valid_bits);
TRACE("MixerCore::OutputFormatChanged:\n"); TRACE("MixerCore::OutputFormatChanged:\n");
TRACE(" fMixBufferFrameRate %ld\n", fMixBufferFrameRate); TRACE(" fMixBufferFrameRate %ld\n", fMixBufferFrameRate);
@@ -274,7 +282,6 @@ void
MixerCore::SetOutputBufferGroup(BBufferGroup *group) MixerCore::SetOutputBufferGroup(BBufferGroup *group)
{ {
ASSERT_LOCKED(); ASSERT_LOCKED();
fBufferGroup = group; fBufferGroup = group;
} }
@@ -282,14 +289,15 @@ void
MixerCore::SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency) MixerCore::SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency)
{ {
ASSERT_LOCKED(); ASSERT_LOCKED();
if (fTimeSource) if (fTimeSource)
fTimeSource->Release(); fTimeSource->Release();
fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire()); fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire());
fDownstreamLatency = downstream_latency; fDownstreamLatency = downstream_latency;
TRACE("MixerCore::SetTimingInfo, now = %Ld, downstream latency %Ld\n", fTimeSource->Now(), fDownstreamLatency); TRACE("MixerCore::SetTimingInfo, now = %Ld, downstream latency %Ld\n",
fTimeSource->Now(),
fDownstreamLatency);
} }
void void
@@ -306,6 +314,7 @@ MixerCore::EnableOutput(bool enabled)
StartMixThread(); StartMixThread();
} }
uint32 uint32
MixerCore::OutputChannelCount() MixerCore::OutputChannelCount()
{ {
@@ -563,12 +572,10 @@ MixerCore::MixThread()
// request a buffer // request a buffer
BBuffer *buf; BBuffer *buf;
{ buf = fBufferGroup->RequestBuffer(
// BStopWatch w("buffer requ"); fOutput->MediaOutput().format.u.raw_audio.buffer_size,
buf = fBufferGroup->RequestBuffer(fOutput->MediaOutput().format.u.raw_audio.buffer_size, buffer_request_timeout); buffer_request_timeout);
}
if (buf) { if (buf) {
// copy data from mix buffer into output buffer // copy data from mix buffer into output buffer
for (int i = 0; i < fMixBufferChannelCount; i++) { for (int i = 0; i < fMixBufferChannelCount; i++) {
fResampler[i]->Resample(reinterpret_cast<char *>(fMixBuffer) + i * sizeof(float), fResampler[i]->Resample(reinterpret_cast<char *>(fMixBuffer) + i * sizeof(float),
@@ -592,11 +599,7 @@ MixerCore::MixThread()
fOutput->AdjustByteOrder(buf); fOutput->AdjustByteOrder(buf);
// send the buffer // send the buffer
status_t res; status_t res = fNode->SendBuffer(buf, fOutput->MediaOutput().destination);
{
// BStopWatch watch("buffer send");
res = fNode->SendBuffer(buf, fOutput->MediaOutput().destination);
}
if (B_OK != res) { if (B_OK != res) {
#if DEBUG #if DEBUG
ERROR("MixerCore: SendBuffer failed for buffer %Ld\n", buffer_num); ERROR("MixerCore: SendBuffer failed for buffer %Ld\n", buffer_num);
@@ -1,10 +1,15 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MIXER_CORE_H #ifndef _MIXER_CORE_H
#define _MIXER_CORE_H #define _MIXER_CORE_H
#include "MixerSettings.h"
#include <Buffer.h> #include <Buffer.h>
#include <Locker.h> #include <Locker.h>
#include <TimeSource.h> #include <TimeSource.h>
#include "MixerSettings.h"
class AudioMixer; class AudioMixer;
class MixerInput; class MixerInput;
@@ -20,7 +25,7 @@ class Resampler;
class MixerCore class MixerCore
{ {
public: public:
MixerCore(AudioMixer *node); MixerCore(AudioMixer *node);
~MixerCore(); ~MixerCore();
@@ -30,56 +35,60 @@ public:
// buffer, this setting is cached in fOutputGain and must be set by // buffer, this setting is cached in fOutputGain and must be set by
// the audio mixer node using SetOutputAttenuation() // the audio mixer node using SetOutputAttenuation()
void SetOutputAttenuation(float gain); void SetOutputAttenuation(float gain);
MixerInput * AddInput(const media_input &input); MixerInput * AddInput(const media_input &input);
MixerOutput * AddOutput(const media_output &output); MixerOutput * AddOutput(const media_output &output);
bool RemoveInput(int32 inputID); bool RemoveInput(int32 inputID);
bool RemoveOutput(); bool RemoveOutput();
int32 CreateInputID(); int32 CreateInputID();
MixerInput *Input(int index); // index = 0 to count-1, NOT inputID // index = 0 to count-1, NOT inputID
MixerOutput *Output(); MixerInput * Input(int index);
MixerOutput * Output();
void Lock(); void Lock();
bool LockWithTimeout(bigtime_t timeout); bool LockWithTimeout(bigtime_t timeout);
bool LockFromMixThread(); bool LockFromMixThread();
void Unlock(); void Unlock();
void BufferReceived(BBuffer *buffer, bigtime_t lateness); void BufferReceived(BBuffer *buffer,
bigtime_t lateness);
void InputFormatChanged(int32 inputID, const media_multi_audio_format &format); void InputFormatChanged(int32 inputID,
void OutputFormatChanged(const media_multi_audio_format &format); const media_multi_audio_format &format);
void OutputFormatChanged(
const media_multi_audio_format &format);
void SetOutputBufferGroup(BBufferGroup *group); void SetOutputBufferGroup(BBufferGroup *group);
void SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency); void SetTimingInfo(BTimeSource *ts,
bigtime_t downstream_latency);
void EnableOutput(bool enabled); void EnableOutput(bool enabled);
bool Start(); bool Start();
bool Stop(); bool Stop();
void StartMixThread(); void StartMixThread();
void StopMixThread(); void StopMixThread();
uint32 OutputChannelCount(); uint32 OutputChannelCount();
private: private:
void ApplyOutputFormat(); void ApplyOutputFormat();
static int32 _mix_thread_(void *arg); static int32 _mix_thread_(void *arg);
void MixThread(); void MixThread();
private: private:
BLocker *fLocker; BLocker *fLocker;
BList *fInputs; BList *fInputs;
MixerOutput *fOutput; MixerOutput *fOutput;
int32 fNextInputID; int32 fNextInputID;
bool fRunning; // true = the mix thread is running // true = the mix thread is running
bool fStarted; // true = mix thread should be started of it is not running bool fRunning;
bool fOutputEnabled; // true = mix thread should be started of it is not running // true = mix thread should be
// started of it is not running
bool fStarted;
// true = mix thread should be
// started of it is not running
bool fOutputEnabled;
Resampler **fResampler; // array Resampler **fResampler; // array
float *fMixBuffer; float *fMixBuffer;
int32 fMixBufferFrameRate; int32 fMixBufferFrameRate;
int32 fMixBufferFrameCount; int32 fMixBufferFrameCount;
@@ -87,36 +96,38 @@ private:
int32 *fMixBufferChannelTypes; //array int32 *fMixBufferChannelTypes; //array
bool fDoubleRateMixing; bool fDoubleRateMixing;
bigtime_t fDownstreamLatency; bigtime_t fDownstreamLatency;
friend class MixerInput; // XXX debug only
MixerSettings *fSettings; MixerSettings *fSettings;
AudioMixer *fNode; AudioMixer *fNode;
BBufferGroup *fBufferGroup; BBufferGroup *fBufferGroup;
BTimeSource *fTimeSource; BTimeSource *fTimeSource;
thread_id fMixThread; thread_id fMixThread;
sem_id fMixThreadWaitSem; sem_id fMixThreadWaitSem;
float fOutputGain; float fOutputGain;
friend class MixerInput; // XXX debug only
}; };
inline void MixerCore::Lock() inline void
MixerCore::Lock()
{ {
fLocker->Lock(); fLocker->Lock();
} }
inline bool MixerCore::LockWithTimeout(bigtime_t timeout) inline bool
MixerCore::LockWithTimeout(bigtime_t timeout)
{ {
return B_OK == fLocker->LockWithTimeout(timeout); return B_OK == fLocker->LockWithTimeout(timeout);
} }
inline void MixerCore::Unlock() inline void
MixerCore::Unlock()
{ {
fLocker->Unlock(); fLocker->Unlock();
} }
inline bool MixerCore::LockFromMixThread() inline bool
MixerCore::LockFromMixThread()
{ {
for (;;) { for (;;) {
if (LockWithTimeout(10000)) if (LockWithTimeout(10000))
@@ -126,5 +137,4 @@ inline bool MixerCore::LockFromMixThread()
return false; return false;
} }
} }
#endif #endif
@@ -1,3 +1,9 @@
/*
* Copyright 2002 David Shipman,
* Copyright 2003-2007 Marcus Overhagen
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MIXER_DEBUG_H_ #ifndef _MIXER_DEBUG_H_
#define _MIXER_DEBUG_H_ #define _MIXER_DEBUG_H_
@@ -1,11 +1,19 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen
*/
#include "ByteSwap.h"
#include "MixerCore.h"
#include "MixerInput.h"
#include "MixerUtils.h"
#include "Resampler.h"
#include <Buffer.h> #include <Buffer.h>
#include <string.h> #include <string.h>
#include <TimeSource.h> // XXX debug only #include <TimeSource.h> // XXX debug only
#include "MixerInput.h"
#include "MixerCore.h"
#include "MixerUtils.h"
#include "Resampler.h"
#include "ByteSwap.h"
MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount) MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount)
: fCore(core), : fCore(core),
@@ -62,8 +70,7 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrame
fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT, 0); fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT, 0);
// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateInputChannelDestinations() // fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateInputChannelDestinations()
SetMixBufferFormat((int32)mixFrameRate, mixFrameCount);
SetMixBufferFormat(mixFrameRate, mixFrameCount);
} }
MixerInput::~MixerInput() MixerInput::~MixerInput()
@@ -125,10 +132,8 @@ MixerInput::BufferReceived(BBuffer *buffer)
if (fLastDataFrameWritten >= 0) { if (fLastDataFrameWritten >= 0) {
int expected_frame = (fLastDataFrameWritten + 1) % fMixBufferFrameCount; int expected_frame = (fLastDataFrameWritten + 1) % fMixBufferFrameCount;
if (offset != expected_frame) { if (offset != expected_frame) {
// due to rounding and other errors, offset might be off by +/- 1 // due to rounding and other errors, offset might be off by +/- 1
// this is not really a bad glitch, we just adjust the position // this is not really a bad glitch, we just adjust the position
if (offset == fLastDataFrameWritten) { if (offset == fLastDataFrameWritten) {
//printf("MixerInput::BufferReceived: -1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset); //printf("MixerInput::BufferReceived: -1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset);
offset = expected_frame; offset = expected_frame;
@@ -169,9 +174,7 @@ MixerInput::BufferReceived(BBuffer *buffer)
} }
//printf("data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames); //printf("data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames);
if (offset + out_frames > fMixBufferFrameCount) { if (offset + out_frames > fMixBufferFrameCount) {
int out_frames1 = fMixBufferFrameCount - offset; int out_frames1 = fMixBufferFrameCount - offset;
int out_frames2 = out_frames - out_frames1; int out_frames2 = out_frames - out_frames1;
int in_frames1 = (out_frames1 * in_frames) / out_frames; int in_frames1 = (out_frames1 * in_frames) / out_frames;
@@ -205,15 +208,12 @@ MixerInput::BufferReceived(BBuffer *buffer)
} }
} else { } else {
//printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", fCore->fTimeSource->Now(), start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames - 1); //printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", fCore->fTimeSource->Now(), start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames - 1);
PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", fCore->fTimeSource->Now(), start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames - 1); PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", fCore->fTimeSource->Now(), start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames - 1);
PRINT(5, " in_frames %5d, out_frames %5d\n", in_frames, out_frames); PRINT(5, " in_frames %5d, out_frames %5d\n", in_frames, out_frames);
fLastDataFrameWritten = offset + out_frames - 1; fLastDataFrameWritten = offset + out_frames - 1;
offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
for (int i = 0; i < fInputChannelCount; i++) { for (int i = 0; i < fInputChannelCount; i++) {
fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio), fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
bytes_per_frame(fInput.format.u.raw_audio), bytes_per_frame(fInput.format.u.raw_audio),
@@ -224,34 +224,36 @@ MixerInput::BufferReceived(BBuffer *buffer)
fInputChannelInfo[i].gain); fInputChannelInfo[i].gain);
} }
} }
fLastDataAvailableTime = start + buffer_duration; fLastDataAvailableTime = start + buffer_duration;
} }
media_input & media_input &
MixerInput::MediaInput() MixerInput::MediaInput()
{ {
return fInput; return fInput;
} }
int32 int32
MixerInput::ID() MixerInput::ID()
{ {
return fInput.destination.id; return fInput.destination.id;
} }
int int
MixerInput::GetInputChannelCount() MixerInput::GetInputChannelCount()
{ {
return fInputChannelCount; return fInputChannelCount;
} }
void void
MixerInput::AddInputChannelDestination(int channel, int destination_type) MixerInput::AddInputChannelDestination(int channel, int destination_type)
{ {
uint32 mask = ChannelTypeToChannelMask(destination_type); uint32 mask = ChannelTypeToChannelMask(destination_type);
// test if the channel is valid
if (channel < 0 || channel >= fInputChannelCount) if (channel < 0 || channel >= fInputChannelCount)
return; return;
@@ -277,7 +279,6 @@ MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
{ {
uint32 mask = ChannelTypeToChannelMask(destination_type); uint32 mask = ChannelTypeToChannelMask(destination_type);
// test if the channel is valid
if (channel < 0 || channel >= fInputChannelCount) if (channel < 0 || channel >= fInputChannelCount)
return; return;
@@ -318,7 +319,6 @@ MixerInput::GetInputChannelForDestination(int destination_type)
int int
MixerInput::GetInputChannelType(int channel) MixerInput::GetInputChannelType(int channel)
{ {
// test if the channel is valid
if (channel < 0 || channel >= fInputChannelCount) if (channel < 0 || channel >= fInputChannelCount)
return 0; return 0;
return GetChannelType(channel, fInputChannelMask); return GetChannelType(channel, fInputChannelMask);
@@ -327,7 +327,6 @@ MixerInput::GetInputChannelType(int channel)
void void
MixerInput::SetInputChannelGain(int channel, float gain) MixerInput::SetInputChannelGain(int channel, float gain)
{ {
// test if the channel is valid
if (channel < 0 || channel >= fInputChannelCount) if (channel < 0 || channel >= fInputChannelCount)
return; return;
if (gain < 0.0f) if (gain < 0.0f)
@@ -339,7 +338,6 @@ MixerInput::SetInputChannelGain(int channel, float gain)
float float
MixerInput::GetInputChannelGain(int channel) MixerInput::GetInputChannelGain(int channel)
{ {
// test if the channel is valid
if (channel < 0 || channel >= fInputChannelCount) if (channel < 0 || channel >= fInputChannelCount)
return 0.0f; return 0.0f;
return fInputChannelInfo[channel].gain; return fInputChannelInfo[channel].gain;
@@ -385,7 +383,6 @@ MixerInput::UpdateInputChannelDestinationMask()
for (int i = 0; i < fInputChannelCount; i++) for (int i = 0; i < fInputChannelCount; i++)
TRACE("UpdateInputChannelDestinationMask: input channel %d, destination_mask 0x%08lX, base %p, gain %.3f\n", i, fInputChannelInfo[i].destination_mask, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); TRACE("UpdateInputChannelDestinationMask: input channel %d, destination_mask 0x%08lX, base %p, gain %.3f\n", i, fInputChannelInfo[i].destination_mask, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
TRACE("UpdateInputChannelDestinationMask: leave\n"); TRACE("UpdateInputChannelDestinationMask: leave\n");
} }
@@ -397,7 +394,6 @@ MixerInput::UpdateInputChannelDestinations()
uint32 mask; uint32 mask;
TRACE("UpdateInputChannelDestinations: enter\n"); TRACE("UpdateInputChannelDestinations: enter\n");
for (int i = 0; i < fInputChannelCount; i++) for (int i = 0; i < fInputChannelCount; i++)
TRACE("UpdateInputChannelDestinations: input channel %d, destination_mask 0x%08lX, base %p, gain %.3f\n", i, fInputChannelInfo[i].destination_mask, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); TRACE("UpdateInputChannelDestinations: input channel %d, destination_mask 0x%08lX, base %p, gain %.3f\n", i, fInputChannelInfo[i].destination_mask, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
@@ -408,9 +404,7 @@ MixerInput::UpdateInputChannelDestinations()
TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits); TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits);
channel_count = count_nonzero_bits(all_bits); channel_count = count_nonzero_bits(all_bits);
TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer channels (%d old)\n", fInputChannelCount, channel_count, fMixerChannelCount); TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer channels (%d old)\n", fInputChannelCount, channel_count, fMixerChannelCount);
if (channel_count != fMixerChannelCount) { if (channel_count != fMixerChannelCount) {
delete [] fMixerChannelInfo; delete [] fMixerChannelInfo;
fMixerChannelInfo = new mixer_chan_info[channel_count]; fMixerChannelInfo = new mixer_chan_info[channel_count];
@@ -448,6 +442,9 @@ MixerInput::UpdateInputChannelDestinations()
TRACE("UpdateInputChannelDestinations: leave\n"); TRACE("UpdateInputChannelDestinations: leave\n");
} }
// Note: The following code is outcommented on purpose
// and is about to be modified at a later point
/* /*
void void
MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, float gain) MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, float gain)
@@ -1,44 +1,58 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MIXER_INPUT_H #ifndef _MIXER_INPUT_H
#define _MIXER_INPUT_H #define _MIXER_INPUT_H
#include <RealtimeAlloc.h>
#include <MediaNode.h>
#include "MixerCore.h" #include "MixerCore.h"
#include "MixerUtils.h" // DEBUG only
#include "MixerDebug.h" #include "MixerDebug.h"
#include "MixerUtils.h"
#include <MediaNode.h>
#include <RealtimeAlloc.h>
class ByteSwap; class ByteSwap;
class Resampler; class Resampler;
class MixerInput class MixerInput
{ {
public: public:
MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount); MixerInput(MixerCore *core,
const media_input &input,
float mixFrameRate,
int32 mixFrameCount);
~MixerInput(); ~MixerInput();
int32 ID(); int32 ID();
void BufferReceived(BBuffer *buffer); void BufferReceived(BBuffer *buffer);
media_input& MediaInput();
media_input & MediaInput();
// The physical input channels // The physical input channels
int GetInputChannelCount(); int GetInputChannelCount();
int GetInputChannelType(int channel); int GetInputChannelType(int channel);
void SetInputChannelGain(int channel, float gain); void SetInputChannelGain(int channel,
float gain);
float GetInputChannelGain(int channel); float GetInputChannelGain(int channel);
// The destinations for each channel // The destinations for each channel
void AddInputChannelDestination(int channel, int destination_type); void AddInputChannelDestination(
void RemoveInputChannelDestination(int channel, int destination_type); int channel,
// void SetInputChannelDestinationGain(int channel, int destination_type, float gain); int destination_type);
// float GetInputChannelDestinationGain(int channel, int destination_type); void RemoveInputChannelDestination(
bool HasInputChannelDestination(int channel, int destination_type); int channel,
int GetInputChannelForDestination(int destination_type); // returns -1 if not found int destination_type);
bool HasInputChannelDestination(
int channel,
int destination_type);
int GetInputChannelForDestination(
int destination_type);
// returns -1 if not found
// The virtual mixer channels that are generated from destinations // The virtual mixer channels that are generated from destinations
int GetMixerChannelCount(); int GetMixerChannelCount();
void SetMixerChannelGain(int mixer_channel, float gain); void SetMixerChannelGain(int mixer_channel,
float gain);
float GetMixerChannelGain(int mixer_channel); float GetMixerChannelGain(int mixer_channel);
int GetMixerChannelType(int mixer_channel); int GetMixerChannelType(int mixer_channel);
@@ -46,17 +60,23 @@ public:
bool IsEnabled(); bool IsEnabled();
// only for use by MixerCore // only for use by MixerCore
bool GetMixerChannelInfo(int mixer_channel, int64 framepos, bigtime_t time, const float **buffer, uint32 *sample_offset, int *type, float *gain); bool GetMixerChannelInfo(int mixer_channel,
int64 framepos,
bigtime_t time,
const float **buffer,
uint32 *sample_offset,
int *type,
float *gain);
protected: protected:
friend class MixerCore; friend class MixerCore;
void SetMixBufferFormat(int32 framerate, int32 frames); void SetMixBufferFormat(int32 framerate,
int32 frames);
private: private:
void UpdateInputChannelDestinationMask(); void UpdateInputChannelDestinationMask();
void UpdateInputChannelDestinations(); void UpdateInputChannelDestinations();
private:
struct input_chan_info { struct input_chan_info {
float *buffer_base; float *buffer_base;
uint32 destination_mask; // multiple or no bits sets uint32 destination_mask; // multiple or no bits sets
@@ -68,37 +88,26 @@ private:
float destination_gain; float destination_gain;
}; };
private: private:
MixerCore *fCore; MixerCore *fCore;
media_input fInput; media_input fInput;
ByteSwap *fInputByteSwap; ByteSwap *fInputByteSwap;
float fChannelTypeGain[MAX_CHANNEL_TYPES]; float fChannelTypeGain[MAX_CHANNEL_TYPES];
bool fEnabled; bool fEnabled;
input_chan_info *fInputChannelInfo; // array input_chan_info *fInputChannelInfo; // array
int fInputChannelCount; int fInputChannelCount;
uint32 fInputChannelMask; uint32 fInputChannelMask;
mixer_chan_info *fMixerChannelInfo; // array mixer_chan_info *fMixerChannelInfo; // array
int fMixerChannelCount; int fMixerChannelCount;
float *fMixBuffer; float *fMixBuffer;
int32 fMixBufferFrameRate; int32 fMixBufferFrameRate;
int fMixBufferFrameCount; int fMixBufferFrameCount;
int32 fLastDataFrameWritten; int32 fLastDataFrameWritten;
bigtime_t fLastDataAvailableTime; bigtime_t fLastDataAvailableTime;
double fFractionalFrames; double fFractionalFrames;
Resampler **fResampler; // array Resampler **fResampler; // array
rtm_pool *fRtmPool; rtm_pool *fRtmPool;
bool fUserOverridesChannelDestinations; bool fUserOverridesChannelDestinations;
int32 debugMixBufferFrames; int32 debugMixBufferFrames;
}; };
@@ -109,9 +118,12 @@ MixerInput::GetMixerChannelCount()
} }
inline bool inline bool
MixerInput::GetMixerChannelInfo(int mixer_channel, int64 framepos, bigtime_t time, const float **buffer, uint32 *sample_offset, int *type, float *gain) MixerInput::GetMixerChannelInfo(int mixer_channel, int64 framepos,
bigtime_t time, const float **buffer,
uint32 *sample_offset, int *type, float *gain)
{ {
ASSERT(fMixBuffer); // this function should not be called if we don't have a mix buffer! // this function should not be called if we don't have a mix buffer!
ASSERT(fMixBuffer);
ASSERT(mixer_channel >= 0 && mixer_channel < fMixerChannelCount); ASSERT(mixer_channel >= 0 && mixer_channel < fMixerChannelCount);
if (!fEnabled) if (!fEnabled)
return false; return false;
@@ -134,5 +146,4 @@ MixerInput::GetMixerChannelInfo(int mixer_channel, int64 framepos, bigtime_t tim
*gain = fMixerChannelInfo[mixer_channel].destination_gain; *gain = fMixerChannelInfo[mixer_channel].destination_gain;
return true; return true;
} }
#endif #endif
@@ -1,8 +1,16 @@
#include <MediaNode.h> /*
#include "MixerOutput.h" * Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* probably Marcus Overhagen
*/
#include "MixerCore.h" #include "MixerCore.h"
#include "MixerUtils.h"
#include "MixerDebug.h" #include "MixerDebug.h"
#include "MixerOutput.h"
#include "MixerUtils.h"
#include <MediaNode.h>
MixerOutput::MixerOutput(MixerCore *core, const media_output &output) MixerOutput::MixerOutput(MixerCore *core, const media_output &output)
: fCore(core), : fCore(core),
@@ -115,7 +123,6 @@ MixerOutput::AssignDefaultSources()
// assign default sources for a few known setups, // assign default sources for a few known setups,
// everything else is left unchanged (it already is 1:1) // everything else is left unchanged (it already is 1:1)
if (count == 1 && mask & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) { if (count == 1 && mask & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) {
// we have only one phycial output channel, and use it as a mix of // we have only one phycial output channel, and use it as a mix of
// left, right, rear-left, rear-right, center and sub // left, right, rear-left, rear-right, center and sub
@@ -1,3 +1,7 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MIXER_OUTPUT_H #ifndef _MIXER_OUTPUT_H
#define _MIXER_OUTPUT_H #define _MIXER_OUTPUT_H
@@ -19,50 +23,59 @@
class MixerOutput class MixerOutput
{ {
public: public:
MixerOutput(MixerCore *core, const media_output &output); MixerOutput(MixerCore *core,
const media_output &output);
~MixerOutput(); ~MixerOutput();
media_output & MediaOutput(); media_output& MediaOutput();
void ChangeFormat(
void ChangeFormat(const media_multi_audio_format &format); const media_multi_audio_format &format);
// The physical output channels // The physical output channels
int GetOutputChannelCount(); int GetOutputChannelCount();
int GetOutputChannelType(int channel); int GetOutputChannelType(int channel);
void SetOutputChannelGain(int channel, float gain); void SetOutputChannelGain(int channel,
float gain);
float GetOutputChannelGain(int channel); float GetOutputChannelGain(int channel);
// The sources for each channel // The sources for each channel
void AddOutputChannelSource(int channel, int source_type); void AddOutputChannelSource(int channel,
void RemoveOutputChannelSource(int channel, int source_type); int source_type);
void SetOutputChannelSourceGain(int channel, int source_type, float source_gain); void RemoveOutputChannelSource(int channel,
float GetOutputChannelSourceGain(int channel, int source_type); int source_type);
bool HasOutputChannelSource(int channel, int source_type); void SetOutputChannelSourceGain(int channel,
int source_type,
float source_gain);
float GetOutputChannelSourceGain(int channel,
int source_type);
bool HasOutputChannelSource(int channel,
int source_type);
// The output can be muted // The output can be muted
void SetMuted(bool yesno); void SetMuted(bool yesno);
bool IsMuted(); bool IsMuted();
// Only for use by MixerCore: // Only for use by MixerCore:
// For iteration of a channel's sources // For iteration of a channel's sources
int GetOutputChannelSourceCount(int channel); int GetOutputChannelSourceCount(int channel);
void GetOutputChannelSourceInfoAt(int channel, int source_index, int *source_type, float *source_gain); void GetOutputChannelSourceInfoAt(int channel,
int source_index,
int *source_type,
float *source_gain);
// To swap byteorder in a buffer is that is needed // To swap byteorder in a buffer is that is needed
void AdjustByteOrder(BBuffer *buffer); void AdjustByteOrder(BBuffer *buffer);
private: private:
void UpdateByteOrderSwap(); void UpdateByteOrderSwap();
void UpdateOutputChannels(); void UpdateOutputChannels();
void AssignDefaultSources(); void AssignDefaultSources();
private: private:
/* An entry in the source array is not the same as the // An entry in the source array is not the same as the
* channel type, but the count should be the same // channel type, but the count should be the same
*/
enum { enum {
MAX_SOURCE_ENTRIES = MAX_CHANNEL_TYPES MAX_SOURCE_ENTRIES = MAX_CHANNEL_TYPES
}; };
@@ -78,33 +91,41 @@ private:
MixerCore *fCore; MixerCore *fCore;
media_output fOutput; media_output fOutput;
int fOutputChannelCount; int fOutputChannelCount;
output_chan_info *fOutputChannelInfo; //array output_chan_info *fOutputChannelInfo; //array
ByteSwap *fOutputByteSwap; ByteSwap *fOutputByteSwap;
bool fMuted; bool fMuted;
}; };
inline int MixerOutput::GetOutputChannelCount()
inline int
MixerOutput::GetOutputChannelCount()
{ {
return fOutputChannelCount; return fOutputChannelCount;
} }
inline float MixerOutput::GetOutputChannelGain(int channel)
inline float
MixerOutput::GetOutputChannelGain(int channel)
{ {
if (channel < 0 || channel >= fOutputChannelCount) if (channel < 0 || channel >= fOutputChannelCount)
return 1.0; return 1.0;
return fOutputChannelInfo[channel].channel_gain; return fOutputChannelInfo[channel].channel_gain;
} }
inline int MixerOutput::GetOutputChannelSourceCount(int channel)
inline int
MixerOutput::GetOutputChannelSourceCount(int channel)
{ {
ASSERT(channel >= 0 && channel < fOutputChannelCount); ASSERT(channel >= 0 && channel < fOutputChannelCount);
return fOutputChannelInfo[channel].source_count; return fOutputChannelInfo[channel].source_count;
} }
inline void MixerOutput::GetOutputChannelSourceInfoAt(int channel, int source_index, int *source_type, float *source_gain)
inline void MixerOutput::GetOutputChannelSourceInfoAt(int channel,
int source_index,
int *source_type,
float *source_gain)
{ {
ASSERT(channel >= 0 && channel < fOutputChannelCount); ASSERT(channel >= 0 && channel < fOutputChannelCount);
ASSERT(source_index >= 0 && source_index < fOutputChannelInfo[channel].source_count); ASSERT(source_index >= 0 && source_index < fOutputChannelInfo[channel].source_count);
@@ -112,13 +133,16 @@ inline void MixerOutput::GetOutputChannelSourceInfoAt(int channel, int source_in
*source_gain = fOutputChannelInfo[channel].source_gain[source_index]; *source_gain = fOutputChannelInfo[channel].source_gain[source_index];
} }
inline void MixerOutput::AdjustByteOrder(BBuffer *buffer)
inline void
MixerOutput::AdjustByteOrder(BBuffer *buffer)
{ {
if (fOutputByteSwap) if (fOutputByteSwap)
fOutputByteSwap->Swap(buffer->Data(), buffer->SizeUsed()); fOutputByteSwap->Swap(buffer->Data(), buffer->SizeUsed());
} }
inline bool MixerOutput::IsMuted() inline bool
MixerOutput::IsMuted()
{ {
return fMuted; return fMuted;
} }
@@ -1,16 +1,22 @@
#include <string.h> /*
* Copyright 2007 Haiku Inc. All rights reserved.
#include <MediaDefs.h> * Distributed under the terms of the MIT License.
#include <Locker.h> *
#include <Path.h> * Authors:
#include <File.h> * probably Marcus Overhagen
#include <OS.h> */
#include "MixerCore.h" #include "MixerCore.h"
#include "MixerDebug.h"
#include "MixerInput.h" #include "MixerInput.h"
#include "MixerOutput.h" #include "MixerOutput.h"
#include "MixerSettings.h" #include "MixerSettings.h"
#include "MixerDebug.h"
#include <File.h>
#include <Locker.h>
#include <MediaDefs.h>
#include <OS.h>
#include <Path.h>
#include <string.h>
#define SAVE_DELAY 5000000 // delay saving of settings for 5s #define SAVE_DELAY 5000000 // delay saving of settings for 5s
#define SAVE_RUNTIME 30000000 // stop save thread after 30s inactivity #define SAVE_RUNTIME 30000000 // stop save thread after 30s inactivity
@@ -268,7 +274,6 @@ MixerSettings::SaveConnectionSettings(MixerInput *input)
// XXX should save channel destinations and mixer channels // XXX should save channel destinations and mixer channels
fLocker->Unlock(); fLocker->Unlock();
StartDeferredSave(); StartDeferredSave();
} }
@@ -301,9 +306,7 @@ MixerSettings::LoadConnectionSettings(MixerInput *input)
// XXX should load channel destinations and mixer channels // XXX should load channel destinations and mixer channels
fInputSetting[index].ReplaceInt64("lru", system_time()); fInputSetting[index].ReplaceInt64("lru", system_time());
fLocker->Unlock(); fLocker->Unlock();
StartDeferredSave(); StartDeferredSave();
} }
@@ -323,7 +326,6 @@ MixerSettings::SaveConnectionSettings(MixerOutput *output)
// XXX should save channel sources and source gains // XXX should save channel sources and source gains
fLocker->Unlock(); fLocker->Unlock();
StartDeferredSave(); StartDeferredSave();
} }
@@ -340,7 +342,6 @@ MixerSettings::LoadConnectionSettings(MixerOutput *output)
} }
// XXX should load channel sources and source gains // XXX should load channel sources and source gains
fLocker->Unlock(); fLocker->Unlock();
} }
@@ -492,7 +493,6 @@ MixerSettings::StartDeferredSave()
resume_thread(fSaveThread); resume_thread(fSaveThread);
fSaveThreadRunning = true; fSaveThreadRunning = true;
fLocker->Unlock(); fLocker->Unlock();
} }
@@ -1,3 +1,7 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MIXER_SETTINGS_H #ifndef _MIXER_SETTINGS_H
#define _MIXER_SETTINGS_H #define _MIXER_SETTINGS_H
@@ -11,7 +15,7 @@ class MixerOutput;
class MixerSettings class MixerSettings
{ {
public: public:
MixerSettings(); MixerSettings();
~MixerSettings(); ~MixerSettings();
@@ -50,8 +54,7 @@ public:
void SaveConnectionSettings(MixerOutput *output); void SaveConnectionSettings(MixerOutput *output);
void LoadConnectionSettings(MixerOutput *output); void LoadConnectionSettings(MixerOutput *output);
protected: protected:
void StartDeferredSave(); void StartDeferredSave();
void StopDeferredSave(); void StopDeferredSave();
@@ -63,7 +66,6 @@ protected:
BLocker *fLocker; BLocker *fLocker;
BPath *fSettingsFile; BPath *fSettingsFile;
volatile bool fSettingsDirty; volatile bool fSettingsDirty;
volatile bigtime_t fSettingsLastChange; volatile bigtime_t fSettingsLastChange;
volatile thread_id fSaveThread; volatile thread_id fSaveThread;
@@ -89,4 +91,4 @@ protected:
BMessage fInputSetting[MAX_INPUT_SETTINGS]; BMessage fInputSetting[MAX_INPUT_SETTINGS];
}; };
#endif //_MIXER_SETTINGS_H #endif