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:
parent
88d9b383f5
commit
bf7ab50d4c
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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_
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user