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

View File

@ -1,26 +1,27 @@
/* AudioMixer
*
* First implementation by David Shipman, 2002
* Rewritten by Marcus Overhagen, 2003
/*
* Copyright 2002 David Shipman,
* Copyright 2003-2007 Marcus Overhagen
* 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 "MixerCore.h"
#include "MixerInput.h"
#include "MixerOutput.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 BUILD_STRING __DATE__ " " __TIME__
@ -34,7 +35,9 @@
#define USE_MEDIA_FORMAT_WORKAROUND 1
#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
#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);
// HandleInputBuffer(buffer, 0);
// buffer->Recycle();
// return;
// Note: The following code is outcommented on purpose
// and is about to be modified at a later point
// HandleInputBuffer(buffer, 0);
// buffer->Recycle();
// return;
// to receive the buffer at the right time,
@ -256,7 +261,9 @@ AudioMixer::BufferReceived(BBuffer *buffer)
void
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) {
printf("Received buffer with way to high lateness %Ld\n", lateness);
if (RunMode() != B_DROP_DATA) {
@ -267,20 +274,22 @@ AudioMixer::HandleInputBuffer(BBuffer *buffer, bigtime_t lateness)
return;
}
}
*/
*/
// printf("Received buffer with lateness %Ld\n", lateness);
// printf("Received buffer with lateness %Ld\n", lateness);
fCore->Lock();
fCore->BufferReceived(buffer, lateness);
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))
{
RequestAdditionalBuffer(channel->fInput.source, buffer);
}
*/
*/
}
void
@ -316,10 +325,11 @@ AudioMixer::GetLatencyFor(const media_destination &for_whom,
*out_latency = EventLatency();
*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;
}
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
// BBufferProducer::PrepareToConnect() should have removed all wildcards.
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();
float frame_rate = output ? output->MediaOutput().format.u.raw_audio.frame_rate : 44100.0f;
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,
// and the port number must match our ControlPort()
@ -366,9 +379,9 @@ AudioMixer::Connected(const media_source &producer, const media_destination &whe
// If we want the producer to use a specific BBufferGroup, we now need to call
// BMediaRoster::SetOutputBuffersFor() here to set the producer's buffer group.
// But we have no special buffer requirements anyway...
UpdateParameterWeb();
return B_OK;
}
@ -376,7 +389,7 @@ void
AudioMixer::Disconnected(const media_source &producer, const media_destination &where)
{
// One of our inputs has been disconnected
// check if it is really belongs to us
if (where.port != ControlPort()) {
TRACE("AudioMixer::Disconnected wrong input port\n");
@ -390,7 +403,6 @@ AudioMixer::Disconnected(const media_source &producer, const media_destination &
}
fCore->Unlock();
UpdateParameterWeb();
}
@ -402,7 +414,7 @@ AudioMixer::FormatChanged(const media_source &producer, const media_destination
// we will receive buffers in a different format
TRACE("AudioMixer::FormatChanged\n");
if (consumer.port != ControlPort() || consumer.id == 0)
return B_MEDIA_BAD_DESTINATION;
@ -467,6 +479,11 @@ AudioMixer::FormatProposal(const media_source &output, media_format *ioFormat)
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
AudioMixer::FormatChangeRequested(const media_source &source, const media_destination &destination,
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) {
ERROR("AudioMixer::FormatChangeRequested: this might be the broken R5 multi audio add-on\n");
goto err;
// fCore->Unlock();
// return B_OK;
} else {
goto err;
}
@ -583,21 +598,23 @@ AudioMixer::GetNextOutput(int32 *cookie, media_output *out_output)
status_t
AudioMixer::DisposeOutputCookie(int32 cookie)
{
// nothin to do
// nothing to do
return B_OK;
}
status_t
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
// BBufferGroup (might be NULL). We only have one output (id 0)
if (for_source.port != ControlPort() || for_source.id != 0)
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;
}
fCore->Lock();
if (!newGroup)
@ -654,11 +671,13 @@ AudioMixer::LatencyChanged(const media_source & source, const media_destination
}
status_t
AudioMixer::PrepareToConnect(const media_source &what, const media_destination &where,
media_format *format, media_source *out_source, char *out_name)
AudioMixer::PrepareToConnect(const media_source &what,
const media_destination &where,
media_format *format,
media_source *out_source,
char *out_name)
{
TRACE("AudioMixer::PrepareToConnect\n");
// PrepareToConnect() is the second stage of format negotiations that happens
// inside BMediaRoster::Connect(). At this point, the consumer's AcceptFormat()
// 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->Unlock();
return B_OK;
}
void
AudioMixer::Connect(status_t error, const media_source &source, const media_destination &dest,
const media_format &format, char *io_name)
AudioMixer::Connect(status_t error, const media_source &source,
const media_destination &dest,
const media_format &format,
char *io_name)
{
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->Unlock();
UpdateParameterWeb();
}
void
AudioMixer::Disconnect(const media_source &what, const media_destination &where)
{
TRACE("AudioMixer::Disconnect\n");
fCore->Lock();
// 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;
}
/* Switch our prefered format back to default
* frame rate and channel count.
*/
// Switch our prefered format back to default
// frame rate and channel count.
fDefaultFormat.u.raw_audio.frame_rate = 96000;
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->Unlock();
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
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 (RunMode() == B_INCREASE_LATENCY) {
fInternalLatency += how_much;
@ -902,7 +916,7 @@ AudioMixer::LateNoticeReceived(const media_source &what, bigtime_t how_much, big
PublishEventLatencyChange();
}
}
*/
*/
}
@ -986,7 +1000,7 @@ AudioMixer::HandleEvent(const media_timed_event *event, bigtime_t lateness, bool
}
}
//
// AudioMixer methods
//
@ -1016,18 +1030,19 @@ AudioMixer::PublishEventLatencyChange()
BBufferGroup *
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;
TRACE("AudioMixer::CreateBufferGroup: fDownstreamLatency %Ld, BufferDuration %Ld, buffer count = %ld\n", fDownstreamLatency, BufferDuration(), count);
if (count < 3)
count = 3;
fCore->Lock();
uint32 size = fCore->Output()->MediaOutput().format.u.raw_audio.buffer_size;
fCore->Unlock();
TRACE("AudioMixer: allocating %ld buffers of %ld bytes each\n", count, size);
return new BBufferGroup(size, count);
}
@ -1672,11 +1687,14 @@ AudioMixer::UpdateParameterWeb()
dp = group->MakeDiscreteParameter(PARAM_ETC(70), B_MEDIA_RAW_AUDIO, "Resampling algorithm", B_INPUT_MUX);
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(2, "Linear interpolation");
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(90), B_MEDIA_RAW_AUDIO, "Refuse input format changes", B_ENABLE);
@ -1691,7 +1709,6 @@ AudioMixer::UpdateParameterWeb()
, B_GENERIC);
fCore->Unlock();
SetParameterWeb(web);
}

View File

@ -1,205 +1,141 @@
// AudioMixer.h
/*
By David Shipman, 2002
*/
* 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 _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;
// 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 :
public BBufferConsumer,
public BBufferProducer,
public BControllable,
public BMediaEventLooper
{
public:
AudioMixer(BMediaAddOn *addOn, bool isSystemMixer);
~AudioMixer();
AudioMixer(BMediaAddOn *addOn, bool isSystemMixer);
~AudioMixer();
void DisableNodeStop();
// AudioMixer support
// AudioMixer support
void ApplySettings();
void PublishEventLatencyChange();
void PublishEventLatencyChange();
void UpdateParameterWeb();
void HandleInputBuffer(BBuffer *buffer, bigtime_t lateness);
BBufferGroup * CreateBufferGroup();
float dB_to_Gain(float db);
float Gain_to_dB(float gain);
// BMediaNode methods
BMediaAddOn * AddOn(int32*) const;
// void SetRunMode(run_mode);
// void Preroll();
// status_t RequestCompleted(const media_request_info & info);
// BMediaNode methods
BMediaAddOn * AddOn(int32 *internal_id) const;
void NodeRegistered();
void Stop(bigtime_t performance_time, bool immediate);
void SetTimeSource(BTimeSource * time_source);
using BBufferProducer::SendBuffer;
protected:
// BControllable methods
status_t GetParameterValue( int32 id, bigtime_t* last_change,
void* value,
size_t* ioSize);
// BControllable methods
status_t GetParameterValue(int32 id,
bigtime_t *last_change,
void *value,
size_t *ioSize);
void SetParameterValue( int32 id, bigtime_t when,
const void* value,
size_t size);
// BBufferConsumer methods
status_t HandleMessage( int32 message,
const void* data,
size_t size);
status_t AcceptFormat( const media_destination &dest, media_format *format);
status_t GetNextInput( int32 *cookie,
media_input *out_input);
void DisposeInputCookie( int32 cookie);
void BufferReceived( BBuffer *buffer);
void ProducerDataStatus( const media_destination &for_whom,
int32 status,
bigtime_t at_performance_time);
status_t GetLatencyFor( const media_destination &for_whom,
bigtime_t *out_latency,
media_node_id *out_timesource);
status_t Connected( const media_source &producer,
const media_destination &where,
const media_format &with_format,
media_input *out_input);
void Disconnected( const media_source &producer,
const media_destination &where);
status_t FormatChanged( const media_source &producer,
const media_destination &consumer,
int32 change_tag,
const media_format &format);
void SetParameterValue(int32 id, bigtime_t when,
const void *value,
size_t size);
//
// BBufferProducer methods
//
status_t FormatSuggestionRequested( media_type type,
int32 quality,
media_format *format);
status_t FormatProposal(
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(
const media_source& source,
const media_destination& destination,
media_format* io_format,
int32* _deprecated_);
// BBufferConsumer methods
status_t HandleMessage(int32 message, const void* data,
size_t size);
status_t AcceptFormat(const media_destination &dest,
media_format *format);
status_t GetNextInput(int32 *cookie,
media_input *out_input);
void DisposeInputCookie(int32 cookie);
void BufferReceived(BBuffer *buffer);
void ProducerDataStatus(const media_destination &for_whom,
int32 status,
bigtime_t at_performance_time);
status_t GetLatencyFor(const media_destination &for_whom,
bigtime_t *out_latency,
media_node_id *out_timesource);
status_t Connected(const media_source &producer,
const media_destination &where,
const media_format &with_format,
media_input *out_input);
void Disconnected(const media_source &producer,
const media_destination &where);
status_t FormatChanged(const media_source &producer,
const media_destination &consumer,
int32 change_tag,
const media_format &format);
status_t GetNextOutput( /* cookie starts as 0 */
int32* cookie,
media_output* out_output);
// BBufferProducer methods
status_t FormatSuggestionRequested(media_type type,
int32 quality,
media_format *format);
status_t FormatProposal(const media_source &output,
media_format *format);
status_t FormatChangeRequested(
const media_source& source,
const media_destination &destination,
media_format *io_format,
int32 *_deprecated_);
status_t GetNextOutput(int32 *cookie,media_output *out_output);
status_t DisposeOutputCookie(int32 cookie);
status_t SetBufferGroup(const media_source &for_source,
BBufferGroup *group);
status_t GetLatency(bigtime_t *out_latency);
status_t PrepareToConnect(const media_source &what,
const media_destination &where,
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 performance_time);
void EnableOutput(const media_source &what,
bool enabled,
int32 *_deprecated_);
void LatencyChanged(const media_source &source,
const media_destination &destination,
bigtime_t new_latency, uint32 flags);
status_t DisposeOutputCookie(
int32 cookie);
// BMediaEventLooper methods
void HandleEvent(const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent = false);
status_t SetBufferGroup(
const media_source& for_source,
BBufferGroup* group);
status_t GetLatency(
bigtime_t* out_latency);
status_t PrepareToConnect(
const media_source& what,
const media_destination& where,
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 performance_time);
void EnableOutput(
const media_source & what,
bool enabled,
int32* _deprecated_);
void LatencyChanged(const media_source & source,
const media_destination & destination,
bigtime_t new_latency, uint32 flags);
// BMediaEventLooper methods
void HandleEvent( const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent = false);
private:
BMediaAddOn *fAddOn;
MixerCore *fCore;
BParameterWeb *fWeb; // local pointer to parameterweb
BBufferGroup *fBufferGroup;
bigtime_t fDownstreamLatency;
bigtime_t fInternalLatency;
bool fDisableStop;
media_format fDefaultFormat;
};
BMediaAddOn *fAddOn;
MixerCore *fCore;
BParameterWeb *fWeb; // local pointer to parameterweb
BBufferGroup *fBufferGroup;
bigtime_t fDownstreamLatency;
bigtime_t fInternalLatency;
bool fDisableStop;
media_format fDefaultFormat;
};
#endif

View File

@ -1,14 +1,14 @@
/* Copyright (C) 2003 Marcus Overhagen
* Released under terms of the MIT license.
*
* A simple byte order swapping class for the audio mixer.
/*
* Copyright 2003-2007 Marcus Overhagen
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <MediaDefs.h>
#include <ByteOrder.h>
#include "ByteSwap.h"
#include "MixerDebug.h"
#include <ByteOrder.h>
#include <MediaDefs.h>
static void swap_float(void *buffer, size_t bytecount);
static void swap_int32(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
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
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
@ -130,5 +132,4 @@ swap_int16(void *buffer, size_t bytecount)
{
swap_data(B_INT16_TYPE, buffer, bytecount, B_SWAP_ALWAYS);
}
#endif

View File

@ -1,22 +1,23 @@
/*
* Copyright 2003-2007 Marcus Overhagen
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _BYTE_SWAP_H
#define _BYTE_SWAP_H
/* Copyright (C) 2003 Marcus Overhagen
* Released under terms of the MIT license.
*
* A simple byte order swapping class for the audio mixer.
*/
#include <SupportDefs.h>
class ByteSwap
{
public:
ByteSwap(uint32 format);
~ByteSwap();
public:
ByteSwap(uint32 format);
~ByteSwap();
void Swap(void *buffer, size_t bytecount);
void Swap(void *buffer, size_t bytecount);
private:
void (*fFunc)(void *, size_t);
private:
void (*fFunc)(void *, size_t);
};
inline void
@ -24,5 +25,4 @@ ByteSwap::Swap(void *buffer, size_t bytecount)
{
(*fFunc)(buffer, bytecount);
}
#endif

View File

@ -1,11 +1,9 @@
// MixerAddOn.cpp
//
// David Shipman, 2002
// Marcus Overhagen, 2003
//
// Allows AudioMixer to be used as an addon.
// The add-on will request to be auto-started.
/*
* Copyright 2002 David Shipman,
* Copyright 2003-2007 Marcus Overhagen
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <MediaRoster.h>
#include <MediaNode.h>
#include <cstring>
@ -19,21 +17,15 @@ extern "C" _EXPORT BMediaAddOn* make_media_addon(image_id image) {
return new AudioMixerAddon(image);
}
// ------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //
AudioMixerAddon::AudioMixerAddon(image_id image)
: BMediaAddOn(image),
fFormat(new media_format),
fInfo(new flavor_info)
: BMediaAddOn(image),
fFormat(new media_format),
fInfo(new flavor_info)
{
// Init media_format
memset(fFormat, 0, sizeof(*fFormat));
fFormat->type = B_MEDIA_RAW_AUDIO;
fFormat->u.raw_audio = media_raw_audio_format::wildcard;
// Init flavor_info
fInfo->internal_id = 0;
fInfo->name = "Audio Mixer (Haiku)";
fInfo->info = "Haiku Audio Mixer media addon";
@ -96,13 +88,12 @@ AudioMixerAddon::GetConfigurationFor(BMediaNode* your_node, BMessage* into_messa
bool
AudioMixerAddon::WantsAutoStart()
{
// yes, please kick me
return true;
}
status_t
AudioMixerAddon::AutoStart(int in_index, BMediaNode ** out_node,
int32 * out_internal_id, bool * out_has_more)
AudioMixerAddon::AutoStart(int in_index, BMediaNode **out_node,
int32 *out_internal_id, bool *out_has_more)
{
*out_has_more = false;

View File

@ -1,49 +1,39 @@
// MixerAddon.h
// David Shipman, 2002
//
// Quick addon header for the Audio Mixer
//
#ifndef __AudioMixerAddOn_H_
#define __AudioMixerAddOn_H_
/*
* 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 _AUDIOMIXER_ADDON_H
#define _AUDIOMIXER_ADDON_H
#include <MediaAddOn.h>
// -------------------------------------------------------- //
class AudioMixerAddon :
public BMediaAddOn {
typedef BMediaAddOn _inherited;
class AudioMixerAddon : public BMediaAddOn {
public:
virtual ~AudioMixerAddon();
explicit AudioMixerAddon(image_id image);
public: // ctor/dtor
virtual ~AudioMixerAddon();
explicit AudioMixerAddon(image_id image);
public: // BMediaAddOn impl
virtual status_t InitCheck(
const char** out_failure_text);
virtual int32 CountFlavors();
virtual status_t GetFlavorAt(
int32 n,
const flavor_info ** out_info);
virtual BMediaNode * InstantiateNodeFor(
const flavor_info * info,
BMessage * config,
status_t * out_error);
virtual status_t GetConfigurationFor(
BMediaNode * your_node,
BMessage * into_message);
virtual status_t InitCheck(const char** out_failure_text);
virtual int32 CountFlavors();
virtual status_t GetFlavorAt(int32 n,
const flavor_info ** out_info);
virtual BMediaNode * InstantiateNodeFor(
const flavor_info *info,
BMessage *config,
status_t *out_error);
virtual status_t GetConfigurationFor(
BMediaNode *your_node,
BMessage *into_message);
virtual bool WantsAutoStart();
virtual status_t AutoStart(
int in_index,
BMediaNode ** out_node,
int32 * out_internal_id,
bool * out_has_more);
virtual bool WantsAutoStart();
virtual status_t AutoStart(int in_index,
BMediaNode **out_node,
int32 *out_internal_id,
bool *out_has_more);
private:
media_format *fFormat;
flavor_info *fInfo;
private:
media_format *fFormat;
flavor_info *fInfo;
};
#endif /*__AudioMixerAddOn_H_*/
#endif

View File

@ -1,19 +1,27 @@
#include <RealtimeAlloc.h>
#include <MediaNode.h>
#include <BufferProducer.h>
#include <TimeSource.h>
#include <Buffer.h>
#include <BufferGroup.h>
#include <StopWatch.h>
#include <string.h>
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen
*/
#include "AudioMixer.h"
#include "MixerCore.h"
#include "MixerInput.h"
#include "MixerOutput.h"
#include "MixerUtils.h"
#include "AudioMixer.h"
#include "Resampler.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
#if DEBUG > 1
@ -49,10 +57,10 @@ MixerCore::MixerCore(AudioMixer *node)
fMixBufferFrameCount(0),
fMixBufferChannelCount(0),
fMixBufferChannelTypes(0),
fDoubleRateMixing(DOUBLE_RATE_MIXING),
fDownstreamLatency(1),
fSettings(new MixerSettings),
fNode(node),
fDoubleRateMixing(DOUBLE_RATE_MIXING),
fDownstreamLatency(1),
fSettings(new MixerSettings),
fNode(node),
fBufferGroup(0),
fTimeSource(0),
fMixThread(-1),
@ -77,7 +85,6 @@ MixerCore::~MixerCore()
if (fTimeSource)
fTimeSource->Release();
// delete resamplers
if (fResampler) {
for (int i = 0; i < fMixBufferChannelCount; i++)
delete fResampler[i];
@ -104,7 +111,8 @@ MixerInput *
MixerCore::AddInput(const media_input &input)
{
ASSERT_LOCKED();
MixerInput *in = new MixerInput(this, input, fMixBufferFrameRate, fMixBufferFrameCount);
MixerInput *in = new MixerInput(this, input, fMixBufferFrameRate,
fMixBufferFrameCount);
fInputs->AddItem(in);
return in;
}
@ -120,7 +128,7 @@ MixerCore::AddOutput(const media_output &output)
fOutput = new MixerOutput(this, output);
// the output format might have been adjusted inside MixerOutput
ApplyOutputFormat();
ASSERT(!fRunning);
if (fStarted && fOutputEnabled)
StartMixThread();
@ -206,7 +214,6 @@ void
MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
{
ASSERT_LOCKED();
bool was_started = fStarted;
if (was_started)
@ -247,16 +254,17 @@ MixerCore::ApplyOutputFormat()
fMixBuffer = (float *)rtm_alloc(NULL, sizeof(float) * fMixBufferFrameCount * fMixBufferChannelCount);
ASSERT(fMixBuffer);
// delete resamplers
if (fResampler) {
for (int i = 0; i < fMixBufferChannelCount; i++)
delete fResampler[i];
delete [] fResampler;
}
// create new resamplers
fResampler = new Resampler * [fMixBufferChannelCount];
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(" fMixBufferFrameRate %ld\n", fMixBufferFrameRate);
@ -274,7 +282,6 @@ void
MixerCore::SetOutputBufferGroup(BBufferGroup *group)
{
ASSERT_LOCKED();
fBufferGroup = group;
}
@ -282,14 +289,15 @@ void
MixerCore::SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency)
{
ASSERT_LOCKED();
if (fTimeSource)
fTimeSource->Release();
fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire());
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
@ -306,6 +314,7 @@ MixerCore::EnableOutput(bool enabled)
StartMixThread();
}
uint32
MixerCore::OutputChannelCount()
{
@ -563,12 +572,10 @@ MixerCore::MixThread()
// request a buffer
BBuffer *buf;
{
// BStopWatch w("buffer requ");
buf = fBufferGroup->RequestBuffer(fOutput->MediaOutput().format.u.raw_audio.buffer_size, buffer_request_timeout);
}
buf = fBufferGroup->RequestBuffer(
fOutput->MediaOutput().format.u.raw_audio.buffer_size,
buffer_request_timeout);
if (buf) {
// copy data from mix buffer into output buffer
for (int i = 0; i < fMixBufferChannelCount; i++) {
fResampler[i]->Resample(reinterpret_cast<char *>(fMixBuffer) + i * sizeof(float),
@ -592,11 +599,7 @@ MixerCore::MixThread()
fOutput->AdjustByteOrder(buf);
// send the buffer
status_t res;
{
// BStopWatch watch("buffer send");
res = fNode->SendBuffer(buf, fOutput->MediaOutput().destination);
}
status_t res = fNode->SendBuffer(buf, fOutput->MediaOutput().destination);
if (B_OK != res) {
#if DEBUG
ERROR("MixerCore: SendBuffer failed for buffer %Ld\n", buffer_num);

View File

@ -1,10 +1,15 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MIXER_CORE_H
#define _MIXER_CORE_H
#include "MixerSettings.h"
#include <Buffer.h>
#include <Locker.h>
#include <TimeSource.h>
#include "MixerSettings.h"
class AudioMixer;
class MixerInput;
@ -20,103 +25,109 @@ class Resampler;
class MixerCore
{
public:
MixerCore(AudioMixer *node);
~MixerCore();
public:
MixerCore(AudioMixer *node);
~MixerCore();
MixerSettings *Settings();
MixerSettings *Settings();
// To avoid calling Settings()->AttenuateOutput() for every outgoing
// buffer, this setting is cached in fOutputGain and must be set by
// the audio mixer node using SetOutputAttenuation()
void SetOutputAttenuation(float gain);
MixerInput * AddInput(const media_input &input);
MixerOutput * AddOutput(const media_output &output);
// To avoid calling Settings()->AttenuateOutput() for every outgoing
// buffer, this setting is cached in fOutputGain and must be set by
// the audio mixer node using SetOutputAttenuation()
void SetOutputAttenuation(float gain);
MixerInput * AddInput(const media_input &input);
MixerOutput * AddOutput(const media_output &output);
bool RemoveInput(int32 inputID);
bool RemoveOutput();
bool RemoveInput(int32 inputID);
bool RemoveOutput();
int32 CreateInputID();
int32 CreateInputID();
// index = 0 to count-1, NOT inputID
MixerInput * Input(int index);
MixerOutput * Output();
MixerInput *Input(int index); // index = 0 to count-1, NOT inputID
MixerOutput *Output();
void Lock();
bool LockWithTimeout(bigtime_t timeout);
bool LockFromMixThread();
void Unlock();
void BufferReceived(BBuffer *buffer, bigtime_t lateness);
void InputFormatChanged(int32 inputID, const media_multi_audio_format &format);
void OutputFormatChanged(const media_multi_audio_format &format);
void Lock();
bool LockWithTimeout(bigtime_t timeout);
bool LockFromMixThread();
void Unlock();
void SetOutputBufferGroup(BBufferGroup *group);
void SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency);
void EnableOutput(bool enabled);
bool Start();
bool Stop();
void BufferReceived(BBuffer *buffer,
bigtime_t lateness);
void StartMixThread();
void StopMixThread();
uint32 OutputChannelCount();
void InputFormatChanged(int32 inputID,
const media_multi_audio_format &format);
void OutputFormatChanged(
const media_multi_audio_format &format);
private:
void ApplyOutputFormat();
static int32 _mix_thread_(void *arg);
void MixThread();
void SetOutputBufferGroup(BBufferGroup *group);
void SetTimingInfo(BTimeSource *ts,
bigtime_t downstream_latency);
void EnableOutput(bool enabled);
bool Start();
bool Stop();
private:
BLocker *fLocker;
BList *fInputs;
MixerOutput *fOutput;
int32 fNextInputID;
bool fRunning; // true = the mix thread is running
bool fStarted; // true = mix thread should be started of it is not running
bool fOutputEnabled; // true = mix thread should be started of it is not running
void StartMixThread();
void StopMixThread();
uint32 OutputChannelCount();
Resampler **fResampler; // array
private:
void ApplyOutputFormat();
static int32 _mix_thread_(void *arg);
void MixThread();
private:
BLocker *fLocker;
BList *fInputs;
MixerOutput *fOutput;
int32 fNextInputID;
// true = the mix thread is running
bool fRunning;
// 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
float *fMixBuffer;
int32 fMixBufferFrameRate;
int32 fMixBufferFrameCount;
int32 fMixBufferChannelCount;
int32 *fMixBufferChannelTypes; //array
bool fDoubleRateMixing;
bigtime_t fDownstreamLatency;
MixerSettings *fSettings;
AudioMixer *fNode;
BBufferGroup *fBufferGroup;
BTimeSource *fTimeSource;
thread_id fMixThread;
sem_id fMixThreadWaitSem;
float fOutputGain;
float *fMixBuffer;
int32 fMixBufferFrameRate;
int32 fMixBufferFrameCount;
int32 fMixBufferChannelCount;
int32 *fMixBufferChannelTypes; //array
bool fDoubleRateMixing;
bigtime_t fDownstreamLatency;
friend class MixerInput; // XXX debug only
MixerSettings *fSettings;
AudioMixer *fNode;
BBufferGroup *fBufferGroup;
BTimeSource *fTimeSource;
thread_id fMixThread;
sem_id fMixThreadWaitSem;
float fOutputGain;
friend class MixerInput; // XXX debug only
};
inline void MixerCore::Lock()
inline void
MixerCore::Lock()
{
fLocker->Lock();
}
inline bool MixerCore::LockWithTimeout(bigtime_t timeout)
inline bool
MixerCore::LockWithTimeout(bigtime_t timeout)
{
return B_OK == fLocker->LockWithTimeout(timeout);
}
inline void MixerCore::Unlock()
inline void
MixerCore::Unlock()
{
fLocker->Unlock();
}
inline bool MixerCore::LockFromMixThread()
inline bool
MixerCore::LockFromMixThread()
{
for (;;) {
if (LockWithTimeout(10000))
@ -126,5 +137,4 @@ inline bool MixerCore::LockFromMixThread()
return false;
}
}
#endif

View File

@ -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_
#define _MIXER_DEBUG_H_

View File

@ -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 <string.h>
#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)
: 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);
// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateInputChannelDestinations()
SetMixBufferFormat(mixFrameRate, mixFrameCount);
SetMixBufferFormat((int32)mixFrameRate, mixFrameCount);
}
MixerInput::~MixerInput()
@ -125,10 +132,8 @@ MixerInput::BufferReceived(BBuffer *buffer)
if (fLastDataFrameWritten >= 0) {
int expected_frame = (fLastDataFrameWritten + 1) % fMixBufferFrameCount;
if (offset != expected_frame) {
// due to rounding and other errors, offset might be off by +/- 1
// this is not really a bad glitch, we just adjust the position
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);
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);
if (offset + out_frames > fMixBufferFrameCount) {
int out_frames1 = fMixBufferFrameCount - offset;
int out_frames2 = out_frames - out_frames1;
int in_frames1 = (out_frames1 * in_frames) / out_frames;
@ -205,15 +208,12 @@ MixerInput::BufferReceived(BBuffer *buffer)
}
} 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);
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);
fLastDataFrameWritten = offset + out_frames - 1;
offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
for (int i = 0; i < fInputChannelCount; i++) {
fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
bytes_per_frame(fInput.format.u.raw_audio),
@ -224,34 +224,36 @@ MixerInput::BufferReceived(BBuffer *buffer)
fInputChannelInfo[i].gain);
}
}
fLastDataAvailableTime = start + buffer_duration;
}
media_input &
MixerInput::MediaInput()
{
return fInput;
}
int32
MixerInput::ID()
{
return fInput.destination.id;
}
int
MixerInput::GetInputChannelCount()
{
return fInputChannelCount;
}
void
MixerInput::AddInputChannelDestination(int channel, int destination_type)
{
uint32 mask = ChannelTypeToChannelMask(destination_type);
// test if the channel is valid
if (channel < 0 || channel >= fInputChannelCount)
return;
@ -277,7 +279,6 @@ MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
{
uint32 mask = ChannelTypeToChannelMask(destination_type);
// test if the channel is valid
if (channel < 0 || channel >= fInputChannelCount)
return;
@ -318,7 +319,6 @@ MixerInput::GetInputChannelForDestination(int destination_type)
int
MixerInput::GetInputChannelType(int channel)
{
// test if the channel is valid
if (channel < 0 || channel >= fInputChannelCount)
return 0;
return GetChannelType(channel, fInputChannelMask);
@ -327,7 +327,6 @@ MixerInput::GetInputChannelType(int channel)
void
MixerInput::SetInputChannelGain(int channel, float gain)
{
// test if the channel is valid
if (channel < 0 || channel >= fInputChannelCount)
return;
if (gain < 0.0f)
@ -339,7 +338,6 @@ MixerInput::SetInputChannelGain(int channel, float gain)
float
MixerInput::GetInputChannelGain(int channel)
{
// test if the channel is valid
if (channel < 0 || channel >= fInputChannelCount)
return 0.0f;
return fInputChannelInfo[channel].gain;
@ -385,7 +383,6 @@ MixerInput::UpdateInputChannelDestinationMask()
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: leave\n");
}
@ -397,7 +394,6 @@ MixerInput::UpdateInputChannelDestinations()
uint32 mask;
TRACE("UpdateInputChannelDestinations: enter\n");
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);
@ -408,9 +404,7 @@ MixerInput::UpdateInputChannelDestinations()
TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits);
channel_count = count_nonzero_bits(all_bits);
TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer channels (%d old)\n", fInputChannelCount, channel_count, fMixerChannelCount);
if (channel_count != fMixerChannelCount) {
delete [] fMixerChannelInfo;
fMixerChannelInfo = new mixer_chan_info[channel_count];
@ -448,6 +442,9 @@ MixerInput::UpdateInputChannelDestinations()
TRACE("UpdateInputChannelDestinations: leave\n");
}
// Note: The following code is outcommented on purpose
// and is about to be modified at a later point
/*
void
MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, float gain)

View File

@ -1,105 +1,114 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MIXER_INPUT_H
#define _MIXER_INPUT_H
#include <RealtimeAlloc.h>
#include <MediaNode.h>
#include "MixerCore.h"
#include "MixerUtils.h" // DEBUG only
#include "MixerDebug.h"
#include "MixerUtils.h"
#include <MediaNode.h>
#include <RealtimeAlloc.h>
class ByteSwap;
class Resampler;
class MixerInput
{
public:
MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount);
~MixerInput();
public:
MixerInput(MixerCore *core,
const media_input &input,
float mixFrameRate,
int32 mixFrameCount);
~MixerInput();
int32 ID();
void BufferReceived(BBuffer *buffer);
media_input & MediaInput();
int32 ID();
void BufferReceived(BBuffer *buffer);
media_input& MediaInput();
// The physical input channels
int GetInputChannelCount();
int GetInputChannelType(int channel);
void SetInputChannelGain(int channel, float gain);
float GetInputChannelGain(int channel);
// The physical input channels
int GetInputChannelCount();
int GetInputChannelType(int channel);
void SetInputChannelGain(int channel,
float gain);
float GetInputChannelGain(int channel);
// The destinations for each channel
void AddInputChannelDestination(int channel, int destination_type);
void RemoveInputChannelDestination(int channel, int destination_type);
// void SetInputChannelDestinationGain(int channel, int destination_type, float gain);
// float GetInputChannelDestinationGain(int channel, int destination_type);
bool HasInputChannelDestination(int channel, int destination_type);
int GetInputChannelForDestination(int destination_type); // returns -1 if not found
// The destinations for each channel
void AddInputChannelDestination(
int channel,
int destination_type);
void RemoveInputChannelDestination(
int channel,
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
int GetMixerChannelCount();
void SetMixerChannelGain(int mixer_channel, float gain);
float GetMixerChannelGain(int mixer_channel);
int GetMixerChannelType(int mixer_channel);
// The virtual mixer channels that are generated from destinations
int GetMixerChannelCount();
void SetMixerChannelGain(int mixer_channel,
float gain);
float GetMixerChannelGain(int mixer_channel);
int GetMixerChannelType(int mixer_channel);
void SetEnabled(bool yesno);
bool IsEnabled();
void SetEnabled(bool yesno);
bool IsEnabled();
// 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);
// 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);
protected:
friend class MixerCore;
void SetMixBufferFormat(int32 framerate, int32 frames);
protected:
friend class MixerCore;
void SetMixBufferFormat(int32 framerate,
int32 frames);
private:
void UpdateInputChannelDestinationMask();
void UpdateInputChannelDestinations();
private:
void UpdateInputChannelDestinationMask();
void UpdateInputChannelDestinations();
private:
struct input_chan_info {
float *buffer_base;
uint32 destination_mask; // multiple or no bits sets
float gain;
};
struct mixer_chan_info {
float *buffer_base;
int destination_type;
float destination_gain;
};
struct input_chan_info {
float *buffer_base;
uint32 destination_mask; // multiple or no bits sets
float gain;
};
struct mixer_chan_info {
float *buffer_base;
int destination_type;
float destination_gain;
};
private:
MixerCore *fCore;
media_input fInput;
ByteSwap *fInputByteSwap;
float fChannelTypeGain[MAX_CHANNEL_TYPES];
bool fEnabled;
input_chan_info *fInputChannelInfo; // array
int fInputChannelCount;
uint32 fInputChannelMask;
mixer_chan_info *fMixerChannelInfo; // array
int fMixerChannelCount;
float *fMixBuffer;
int32 fMixBufferFrameRate;
int fMixBufferFrameCount;
int32 fLastDataFrameWritten;
bigtime_t fLastDataAvailableTime;
double fFractionalFrames;
Resampler **fResampler; // array
rtm_pool *fRtmPool;
bool fUserOverridesChannelDestinations;
int32 debugMixBufferFrames;
private:
MixerCore *fCore;
media_input fInput;
ByteSwap *fInputByteSwap;
float fChannelTypeGain[MAX_CHANNEL_TYPES];
bool fEnabled;
input_chan_info *fInputChannelInfo; // array
int fInputChannelCount;
uint32 fInputChannelMask;
mixer_chan_info *fMixerChannelInfo; // array
int fMixerChannelCount;
float *fMixBuffer;
int32 fMixBufferFrameRate;
int fMixBufferFrameCount;
int32 fLastDataFrameWritten;
bigtime_t fLastDataAvailableTime;
double fFractionalFrames;
Resampler **fResampler; // array
rtm_pool *fRtmPool;
bool fUserOverridesChannelDestinations;
int32 debugMixBufferFrames;
};
inline int
@ -109,9 +118,12 @@ MixerInput::GetMixerChannelCount()
}
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);
if (!fEnabled)
return false;
@ -134,5 +146,4 @@ MixerInput::GetMixerChannelInfo(int mixer_channel, int64 framepos, bigtime_t tim
*gain = fMixerChannelInfo[mixer_channel].destination_gain;
return true;
}
#endif

View File

@ -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 "MixerUtils.h"
#include "MixerDebug.h"
#include "MixerOutput.h"
#include "MixerUtils.h"
#include <MediaNode.h>
MixerOutput::MixerOutput(MixerCore *core, const media_output &output)
: fCore(core),
@ -81,7 +89,7 @@ MixerOutput::UpdateOutputChannels()
}
AssignDefaultSources();
// apply old gains and sources, overriding the 1.0 gain defaults for the old channels
if (oldInfo != 0 && oldCount != 0) {
for (int i = 0; i < fOutputChannelCount; i++) {
@ -115,7 +123,6 @@ MixerOutput::AssignDefaultSources()
// assign default sources for a few known setups,
// everything else is left unchanged (it already is 1:1)
if (count == 1 && mask & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) {
// we have only one phycial output channel, and use it as a mix of
// left, right, rear-left, rear-right, center and sub

View File

@ -1,3 +1,7 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MIXER_OUTPUT_H
#define _MIXER_OUTPUT_H
@ -19,92 +23,109 @@
class MixerOutput
{
public:
MixerOutput(MixerCore *core, const media_output &output);
~MixerOutput();
public:
MixerOutput(MixerCore *core,
const media_output &output);
~MixerOutput();
media_output & MediaOutput();
void ChangeFormat(const media_multi_audio_format &format);
// The physical output channels
int GetOutputChannelCount();
int GetOutputChannelType(int channel);
void SetOutputChannelGain(int channel, float gain);
float GetOutputChannelGain(int channel);
// The sources for each channel
void AddOutputChannelSource(int channel, int source_type);
void RemoveOutputChannelSource(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
void SetMuted(bool yesno);
bool IsMuted();
media_output& MediaOutput();
void ChangeFormat(
const media_multi_audio_format &format);
// Only for use by MixerCore:
// For iteration of a channel's sources
int GetOutputChannelSourceCount(int channel);
void GetOutputChannelSourceInfoAt(int channel, int source_index, int *source_type, float *source_gain);
// To swap byteorder in a buffer is that is needed
void AdjustByteOrder(BBuffer *buffer);
private:
void UpdateByteOrderSwap();
void UpdateOutputChannels();
void AssignDefaultSources();
// The physical output channels
int GetOutputChannelCount();
int GetOutputChannelType(int channel);
void SetOutputChannelGain(int channel,
float gain);
float GetOutputChannelGain(int channel);
private:
// The sources for each channel
void AddOutputChannelSource(int channel,
int source_type);
void RemoveOutputChannelSource(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);
/* An entry in the source array is not the same as the
* channel type, but the count should be the same
*/
enum {
MAX_SOURCE_ENTRIES = MAX_CHANNEL_TYPES
};
// The output can be muted
void SetMuted(bool yesno);
bool IsMuted();
struct output_chan_info {
int channel_type;
float channel_gain;
int source_count;
float source_gain[MAX_SOURCE_ENTRIES];
int source_type[MAX_SOURCE_ENTRIES];
float source_gain_cache[MAX_CHANNEL_TYPES];
};
// Only for use by MixerCore:
// For iteration of a channel's sources
int GetOutputChannelSourceCount(int channel);
void GetOutputChannelSourceInfoAt(int channel,
int source_index,
int *source_type,
float *source_gain);
MixerCore *fCore;
media_output fOutput;
int fOutputChannelCount;
output_chan_info *fOutputChannelInfo; //array
ByteSwap *fOutputByteSwap;
bool fMuted;
// To swap byteorder in a buffer is that is needed
void AdjustByteOrder(BBuffer *buffer);
private:
void UpdateByteOrderSwap();
void UpdateOutputChannels();
void AssignDefaultSources();
private:
// An entry in the source array is not the same as the
// channel type, but the count should be the same
enum {
MAX_SOURCE_ENTRIES = MAX_CHANNEL_TYPES
};
struct output_chan_info {
int channel_type;
float channel_gain;
int source_count;
float source_gain[MAX_SOURCE_ENTRIES];
int source_type[MAX_SOURCE_ENTRIES];
float source_gain_cache[MAX_CHANNEL_TYPES];
};
MixerCore *fCore;
media_output fOutput;
int fOutputChannelCount;
output_chan_info *fOutputChannelInfo; //array
ByteSwap *fOutputByteSwap;
bool fMuted;
};
inline int MixerOutput::GetOutputChannelCount()
inline int
MixerOutput::GetOutputChannelCount()
{
return fOutputChannelCount;
}
inline float MixerOutput::GetOutputChannelGain(int channel)
inline float
MixerOutput::GetOutputChannelGain(int channel)
{
if (channel < 0 || channel >= fOutputChannelCount)
return 1.0;
return fOutputChannelInfo[channel].channel_gain;
}
inline int MixerOutput::GetOutputChannelSourceCount(int channel)
inline int
MixerOutput::GetOutputChannelSourceCount(int channel)
{
ASSERT(channel >= 0 && channel < fOutputChannelCount);
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(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];
}
inline void MixerOutput::AdjustByteOrder(BBuffer *buffer)
inline void
MixerOutput::AdjustByteOrder(BBuffer *buffer)
{
if (fOutputByteSwap)
fOutputByteSwap->Swap(buffer->Data(), buffer->SizeUsed());
}
inline bool MixerOutput::IsMuted()
inline bool
MixerOutput::IsMuted()
{
return fMuted;
}

View File

@ -1,16 +1,22 @@
#include <string.h>
#include <MediaDefs.h>
#include <Locker.h>
#include <Path.h>
#include <File.h>
#include <OS.h>
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* probably Marcus Overhagen
*/
#include "MixerCore.h"
#include "MixerDebug.h"
#include "MixerInput.h"
#include "MixerOutput.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_RUNTIME 30000000 // stop save thread after 30s inactivity
@ -268,7 +274,6 @@ MixerSettings::SaveConnectionSettings(MixerInput *input)
// XXX should save channel destinations and mixer channels
fLocker->Unlock();
StartDeferredSave();
}
@ -301,9 +306,7 @@ MixerSettings::LoadConnectionSettings(MixerInput *input)
// XXX should load channel destinations and mixer channels
fInputSetting[index].ReplaceInt64("lru", system_time());
fLocker->Unlock();
StartDeferredSave();
}
@ -323,7 +326,6 @@ MixerSettings::SaveConnectionSettings(MixerOutput *output)
// XXX should save channel sources and source gains
fLocker->Unlock();
StartDeferredSave();
}
@ -340,7 +342,6 @@ MixerSettings::LoadConnectionSettings(MixerOutput *output)
}
// XXX should load channel sources and source gains
fLocker->Unlock();
}
@ -492,7 +493,6 @@ MixerSettings::StartDeferredSave()
resume_thread(fSaveThread);
fSaveThreadRunning = true;
fLocker->Unlock();
}

View File

@ -1,3 +1,7 @@
/*
* Copyright 2007 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MIXER_SETTINGS_H
#define _MIXER_SETTINGS_H
@ -11,82 +15,80 @@ class MixerOutput;
class MixerSettings
{
public:
MixerSettings();
~MixerSettings();
public:
MixerSettings();
~MixerSettings();
void SetSettingsFile(const char *file);
void SetSettingsFile(const char *file);
bool AttenuateOutput();
void SetAttenuateOutput(bool yesno);
bool AttenuateOutput();
void SetAttenuateOutput(bool yesno);
bool NonLinearGainSlider();
void SetNonLinearGainSlider(bool yesno);
bool NonLinearGainSlider();
void SetNonLinearGainSlider(bool yesno);
bool UseBalanceControl();
void SetUseBalanceControl(bool yesno);
bool UseBalanceControl();
void SetUseBalanceControl(bool yesno);
bool AllowOutputChannelRemapping();
void SetAllowOutputChannelRemapping(bool yesno);
bool AllowOutputChannelRemapping();
void SetAllowOutputChannelRemapping(bool yesno);
bool AllowInputChannelRemapping();
void SetAllowInputChannelRemapping(bool yesno);
bool AllowInputChannelRemapping();
void SetAllowInputChannelRemapping(bool yesno);
int InputGainControls();
void SetInputGainControls(int value);
int InputGainControls();
void SetInputGainControls(int value);
int ResamplingAlgorithm();
void SetResamplingAlgorithm(int value);
int ResamplingAlgorithm();
void SetResamplingAlgorithm(int value);
bool RefuseOutputFormatChange();
void SetRefuseOutputFormatChange(bool yesno);
bool RefuseOutputFormatChange();
void SetRefuseOutputFormatChange(bool yesno);
bool RefuseInputFormatChange();
void SetRefuseInputFormatChange(bool yesno);
bool RefuseInputFormatChange();
void SetRefuseInputFormatChange(bool yesno);
void SaveConnectionSettings(MixerInput *input);
void LoadConnectionSettings(MixerInput *input);
void SaveConnectionSettings(MixerInput *input);
void LoadConnectionSettings(MixerInput *input);
void SaveConnectionSettings(MixerOutput *output);
void LoadConnectionSettings(MixerOutput *output);
void SaveConnectionSettings(MixerOutput *output);
void LoadConnectionSettings(MixerOutput *output);
protected:
void StartDeferredSave();
void StopDeferredSave();
protected:
void StartDeferredSave();
void StopDeferredSave();
void Save();
void Load();
void Save();
void Load();
static int32 _save_thread_(void *arg);
void SaveThread();
static int32 _save_thread_(void *arg);
void SaveThread();
BLocker *fLocker;
BPath *fSettingsFile;
BLocker *fLocker;
BPath *fSettingsFile;
volatile bool fSettingsDirty;
volatile bigtime_t fSettingsLastChange;
volatile thread_id fSaveThread;
volatile sem_id fSaveThreadWaitSem;
volatile bool fSaveThreadRunning;
volatile bool fSettingsDirty;
volatile bigtime_t fSettingsLastChange;
volatile thread_id fSaveThread;
volatile sem_id fSaveThreadWaitSem;
volatile bool fSaveThreadRunning;
struct settings
{
bool AttenuateOutput;
bool NonLinearGainSlider;
bool UseBalanceControl;
bool AllowOutputChannelRemapping;
bool AllowInputChannelRemapping;
int InputGainControls;
int ResamplingAlgorithm;
bool RefuseOutputFormatChange;
bool RefuseInputFormatChange;
};
struct settings
{
bool AttenuateOutput;
bool NonLinearGainSlider;
bool UseBalanceControl;
bool AllowOutputChannelRemapping;
bool AllowInputChannelRemapping;
int InputGainControls;
int ResamplingAlgorithm;
bool RefuseOutputFormatChange;
bool RefuseInputFormatChange;
};
volatile settings fSettings;
volatile settings fSettings;
BMessage fOutputSetting;
BMessage fInputSetting[MAX_INPUT_SETTINGS];
BMessage fOutputSetting;
BMessage fInputSetting[MAX_INPUT_SETTINGS];
};
#endif //_MIXER_SETTINGS_H
#endif