added mixer gain controls
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3775 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -99,23 +99,6 @@ AudioMixer::AddOn(int32 *internal_id) const
|
|||||||
return fAddOn;
|
return fAddOn;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// BControllable methods
|
|
||||||
//
|
|
||||||
|
|
||||||
status_t
|
|
||||||
AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change,
|
|
||||||
void *value, size_t *ioSize)
|
|
||||||
{
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AudioMixer::SetParameterValue(int32 id, bigtime_t when,
|
|
||||||
const void *value, size_t size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// BBufferConsumer methods
|
// BBufferConsumer methods
|
||||||
//
|
//
|
||||||
@@ -308,11 +291,13 @@ AudioMixer::Connected(const media_source &producer, const media_destination &whe
|
|||||||
fCore->AddInput(*out_input);
|
fCore->AddInput(*out_input);
|
||||||
|
|
||||||
fCore->Unlock();
|
fCore->Unlock();
|
||||||
|
|
||||||
// If we want the producer to use a specific BBufferGroup, we now need to call
|
// 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.
|
// BMediaRoster::SetOutputBuffersFor() here to set the producer's buffer group.
|
||||||
// But we have no special buffer requirements anyway...
|
// But we have no special buffer requirements anyway...
|
||||||
|
|
||||||
|
UpdateParameterWeb();
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,6 +319,8 @@ AudioMixer::Disconnected(const media_source &producer, const media_destination &
|
|||||||
}
|
}
|
||||||
|
|
||||||
fCore->Unlock();
|
fCore->Unlock();
|
||||||
|
|
||||||
|
UpdateParameterWeb();
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
@@ -686,6 +673,8 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest
|
|||||||
fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
|
fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
|
||||||
fCore->SetOutputBufferGroup(fBufferGroup);
|
fCore->SetOutputBufferGroup(fBufferGroup);
|
||||||
fCore->Unlock();
|
fCore->Unlock();
|
||||||
|
|
||||||
|
UpdateParameterWeb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -716,6 +705,8 @@ AudioMixer::Disconnect(const media_source &what, const media_destination &where)
|
|||||||
fCore->SetOutputBufferGroup(0);
|
fCore->SetOutputBufferGroup(0);
|
||||||
|
|
||||||
fCore->Unlock();
|
fCore->Unlock();
|
||||||
|
|
||||||
|
UpdateParameterWeb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -772,6 +763,7 @@ AudioMixer::NodeRegistered()
|
|||||||
#else
|
#else
|
||||||
SetPriority(120);
|
SetPriority(120);
|
||||||
#endif
|
#endif
|
||||||
|
UpdateParameterWeb();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -848,6 +840,197 @@ AudioMixer::CreateBufferGroup()
|
|||||||
return new BBufferGroup(size, count);
|
return new BBufferGroup(size, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// BControllable methods
|
||||||
|
//
|
||||||
|
|
||||||
|
#define PARAM_INPUT(a) (10*(a) + 0)
|
||||||
|
#define PARAM_FORMAT(a) (10*(a) + 1)
|
||||||
|
#define PARAM_MUTE(a) (10*(a) + 2)
|
||||||
|
#define PARAM_GAIN(a) (10*(a) + 3)
|
||||||
|
#define PARAM_OUTPUT(a) (10*(a) + 4)
|
||||||
|
#define PARAM(a) ((a) / 10)
|
||||||
|
#define PARAM_IS_MUTE(a) ((a) % 10 == 2)
|
||||||
|
#define PARAM_IS_GAIN(a) ((a) % 10 == 3)
|
||||||
|
#define DB_TO_GAIN(_db) (20.0 * log10(_db))
|
||||||
|
#define GAIN_TO_DB(_gain) (pow(10.0, (_gain) / 20.0))
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change,
|
||||||
|
void *value, size_t *ioSize)
|
||||||
|
{
|
||||||
|
TRACE("GetParameterValue: id %ld, ioSize %ld\n", id, *ioSize);
|
||||||
|
int param = PARAM(id);
|
||||||
|
fCore->Lock();
|
||||||
|
if (param == 0) {
|
||||||
|
MixerOutput *output = fCore->Output();
|
||||||
|
if ((!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id)) || !output)
|
||||||
|
goto err;
|
||||||
|
if (PARAM_IS_MUTE(id)) {
|
||||||
|
// output mute control
|
||||||
|
printf("get output mute control size %d\n", *ioSize);
|
||||||
|
if (*ioSize < sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = 0;
|
||||||
|
}
|
||||||
|
if (PARAM_IS_GAIN(id)) {
|
||||||
|
// output gain control
|
||||||
|
if (*ioSize < output->GetOutputChannelCount() * sizeof(float))
|
||||||
|
goto err;
|
||||||
|
*ioSize = output->GetOutputChannelCount() * sizeof(float);
|
||||||
|
for (int chan = 0; chan < output->GetOutputChannelCount(); chan++)
|
||||||
|
static_cast<float *>(value)[chan] = DB_TO_GAIN(output->GetOutputChannelGain(chan));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MixerInput *input;
|
||||||
|
for (int i = 0; (input = fCore->Input(i)); i++)
|
||||||
|
if (input->ID() == param)
|
||||||
|
break;
|
||||||
|
if ((!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id)) || !input)
|
||||||
|
goto err;
|
||||||
|
if (PARAM_IS_MUTE(id)) {
|
||||||
|
// input mute control
|
||||||
|
printf("get input mute control size %d\n", *ioSize);
|
||||||
|
if (*ioSize < sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = 0;
|
||||||
|
}
|
||||||
|
if (PARAM_IS_GAIN(id)) {
|
||||||
|
// input gain control
|
||||||
|
if (*ioSize < input->GetMixerChannelCount() * sizeof(float))
|
||||||
|
goto err;
|
||||||
|
*ioSize = input->GetMixerChannelCount() * sizeof(float);
|
||||||
|
for (int chan = 0; chan < input->GetMixerChannelCount(); chan++)
|
||||||
|
static_cast<float *>(value)[chan] = DB_TO_GAIN(input->GetMixerChannelGain(chan));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*last_change = TimeSource()->Now(); // XXX we could do better
|
||||||
|
fCore->Unlock();
|
||||||
|
return B_OK;
|
||||||
|
err:
|
||||||
|
fCore->Unlock();
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioMixer::SetParameterValue(int32 id, bigtime_t when,
|
||||||
|
const void *value, size_t size)
|
||||||
|
{
|
||||||
|
TRACE("SetParameterValue: id %ld, size %ld\n", id, size);
|
||||||
|
int param = PARAM(id);
|
||||||
|
fCore->Lock();
|
||||||
|
if (param == 0) {
|
||||||
|
MixerOutput *output = fCore->Output();
|
||||||
|
if ((!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id)) || !output)
|
||||||
|
goto err;
|
||||||
|
if (PARAM_IS_MUTE(id)) {
|
||||||
|
// output mute control
|
||||||
|
printf("set output mute control size %d\n", size);
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (PARAM_IS_GAIN(id)) {
|
||||||
|
// output gain control
|
||||||
|
if (size < output->GetOutputChannelCount() * sizeof(float))
|
||||||
|
goto err;
|
||||||
|
for (int chan = 0; chan < output->GetOutputChannelCount(); chan++)
|
||||||
|
output->SetOutputChannelGain(chan, GAIN_TO_DB(static_cast<float *>(value)[chan]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MixerInput *input;
|
||||||
|
for (int i = 0; (input = fCore->Input(i)); i++)
|
||||||
|
if (input->ID() == param)
|
||||||
|
break;
|
||||||
|
if ((!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id)) || !input)
|
||||||
|
goto err;
|
||||||
|
if (PARAM_IS_MUTE(id)) {
|
||||||
|
// input mute control
|
||||||
|
printf("set input mute control size %d\n", size);
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (PARAM_IS_GAIN(id)) {
|
||||||
|
// input gain control
|
||||||
|
if (size < input->GetMixerChannelCount() * sizeof(float))
|
||||||
|
goto err;
|
||||||
|
for (int chan = 0; chan < input->GetMixerChannelCount(); chan++)
|
||||||
|
input->SetMixerChannelGain(chan, GAIN_TO_DB(static_cast<float *>(value)[chan]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BroadcastNewParameterValue(when, id, const_cast<void *>(value), size);
|
||||||
|
err:
|
||||||
|
fCore->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioMixer::UpdateParameterWeb()
|
||||||
|
{
|
||||||
|
fCore->Lock();
|
||||||
|
BParameterWeb *web = new BParameterWeb();
|
||||||
|
BParameterGroup *top;
|
||||||
|
BParameterGroup *output;
|
||||||
|
BParameterGroup *inputs;
|
||||||
|
BParameterGroup *outputchannels;
|
||||||
|
BParameterGroup *inputchannels;
|
||||||
|
BParameterGroup *group;
|
||||||
|
MixerInput *in;
|
||||||
|
MixerOutput *out;
|
||||||
|
|
||||||
|
top = web->MakeGroup("Gain Controls"); // top level group
|
||||||
|
output = top->MakeGroup("");
|
||||||
|
inputs = top->MakeGroup("");
|
||||||
|
|
||||||
|
group = output->MakeGroup("");
|
||||||
|
out = fCore->Output();
|
||||||
|
if (!out) {
|
||||||
|
group->MakeNullParameter(PARAM_INPUT(0), B_MEDIA_RAW_AUDIO, "Master Gain", B_WEB_BUFFER_INPUT);
|
||||||
|
group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC);
|
||||||
|
} else {
|
||||||
|
group->MakeNullParameter(PARAM_INPUT(0), B_MEDIA_RAW_AUDIO, "Master Gain", B_WEB_BUFFER_INPUT);
|
||||||
|
group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, StringForFormat(out), B_GENERIC);
|
||||||
|
group->MakeDiscreteParameter(PARAM_MUTE(0), B_MEDIA_RAW_AUDIO, "Mute", B_MUTE);
|
||||||
|
group->MakeContinuousParameter(PARAM_GAIN(0), B_MEDIA_RAW_AUDIO, "Gain", B_GAIN, "dB", -60.0, 18.0, 0.5)
|
||||||
|
->SetChannelCount(out->GetOutputChannelCount());
|
||||||
|
group->MakeNullParameter(PARAM_OUTPUT(0), B_MEDIA_RAW_AUDIO, "To Output", B_WEB_BUFFER_OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fCore->Input(0)) {
|
||||||
|
//group = inputs->MakeGroup("");
|
||||||
|
//group->MakeNullParameter(100, B_MEDIA_RAW_AUDIO, "Input", B_WEB_BUFFER_INPUT);
|
||||||
|
//group->MakeNullParameter(100, B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC);
|
||||||
|
}
|
||||||
|
for (int i = 0; (in = fCore->Input(i)); i++) {
|
||||||
|
group = inputs->MakeGroup("");
|
||||||
|
group->MakeNullParameter(PARAM_INPUT(in->ID()), B_MEDIA_RAW_AUDIO, in->MediaInput().name, B_WEB_BUFFER_INPUT);
|
||||||
|
group->MakeNullParameter(PARAM_FORMAT(in->ID()), B_MEDIA_RAW_AUDIO, StringForFormat(in), B_GENERIC);
|
||||||
|
group->MakeDiscreteParameter(PARAM_MUTE(in->ID()), B_MEDIA_RAW_AUDIO, "Mute", B_MUTE);
|
||||||
|
group->MakeContinuousParameter(PARAM_GAIN(in->ID()), B_MEDIA_RAW_AUDIO, "Gain", B_GAIN, "dB", -60.0, 18.0, 0.5)
|
||||||
|
->SetChannelCount(in->GetMixerChannelCount());
|
||||||
|
group->MakeNullParameter(PARAM_OUTPUT(in->ID()), B_MEDIA_RAW_AUDIO, "To Master", B_WEB_BUFFER_OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
top = web->MakeGroup("Output Channels"); // top level group
|
||||||
|
outputchannels = top->MakeGroup("");
|
||||||
|
group = outputchannels->MakeGroup("");
|
||||||
|
|
||||||
|
group->MakeNullParameter(10001, B_MEDIA_RAW_AUDIO, "Output Channel Sources", B_WEB_BUFFER_OUTPUT);
|
||||||
|
|
||||||
|
top = web->MakeGroup("Input Channels"); // top level group
|
||||||
|
inputchannels = top->MakeGroup("");
|
||||||
|
|
||||||
|
group = inputchannels->MakeGroup("");
|
||||||
|
group->MakeNullParameter(10002, B_MEDIA_RAW_AUDIO, "Input Channel Sources 0", B_WEB_BUFFER_OUTPUT);
|
||||||
|
|
||||||
|
group = inputchannels->MakeGroup("");
|
||||||
|
group->MakeNullParameter(10003, B_MEDIA_RAW_AUDIO, "Input Channel Sources 1", B_WEB_BUFFER_OUTPUT);
|
||||||
|
|
||||||
|
SetParameterWeb(web);
|
||||||
|
|
||||||
|
fCore->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
#if USE_MEDIA_FORMAT_WORKAROUND
|
#if USE_MEDIA_FORMAT_WORKAROUND
|
||||||
static void
|
static void
|
||||||
raw_audio_format_specialize(media_raw_audio_format *format, const media_raw_audio_format *other)
|
raw_audio_format_specialize(media_raw_audio_format *format, const media_raw_audio_format *other)
|
||||||
|
|||||||
@@ -42,8 +42,7 @@ class AudioMixer :
|
|||||||
|
|
||||||
// AudioMixer support
|
// AudioMixer support
|
||||||
|
|
||||||
|
void UpdateParameterWeb();
|
||||||
BParameterWeb * BuildParameterWeb(); // used to create the initial 'master' web
|
|
||||||
void MakeWebForInput(char *name, media_format format);
|
void MakeWebForInput(char *name, media_format format);
|
||||||
|
|
||||||
void HandleInputBuffer(BBuffer *buffer, bigtime_t lateness);
|
void HandleInputBuffer(BBuffer *buffer, bigtime_t lateness);
|
||||||
|
|||||||
@@ -536,7 +536,7 @@ MixerCore::MixThread()
|
|||||||
reinterpret_cast<char *>(buf->Data()) + (i * bytes_per_sample(fOutput->MediaOutput().format.u.raw_audio)),
|
reinterpret_cast<char *>(buf->Data()) + (i * bytes_per_sample(fOutput->MediaOutput().format.u.raw_audio)),
|
||||||
bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio),
|
bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio),
|
||||||
frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio),
|
frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio),
|
||||||
1.0);
|
fOutput->GetOutputChannelGain(i));
|
||||||
}
|
}
|
||||||
PRINT(4, "send buffer, inframes %ld, outframes %ld\n", fMixBufferFrameCount, frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio));
|
PRINT(4, "send buffer, inframes %ld, outframes %ld\n", fMixBufferFrameCount, frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio));
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#include <MediaNode.h>
|
|
||||||
#include <Buffer.h>
|
#include <Buffer.h>
|
||||||
#include <RealtimeAlloc.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <TimeSource.h> // XXX debug only
|
#include <TimeSource.h> // XXX debug only
|
||||||
#include "MixerInput.h"
|
#include "MixerInput.h"
|
||||||
@@ -423,6 +421,7 @@ MixerInput::GetMixerChannelCount()
|
|||||||
void
|
void
|
||||||
MixerInput::SetMixerChannelGain(int channel, float gain)
|
MixerInput::SetMixerChannelGain(int channel, float gain)
|
||||||
{
|
{
|
||||||
|
TRACE("SetMixerChannelGain chan %d, gain %.5f\n", channel, gain);
|
||||||
if (channel < 0 || channel >= fMixerChannelCount)
|
if (channel < 0 || channel >= fMixerChannelCount)
|
||||||
return;
|
return;
|
||||||
if (gain < 0.0f)
|
if (gain < 0.0f)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef _MIXER_INPUT_H
|
#ifndef _MIXER_INPUT_H
|
||||||
#define _MIXER_INPUT_H
|
#define _MIXER_INPUT_H
|
||||||
|
|
||||||
|
#include <RealtimeAlloc.h>
|
||||||
|
#include <MediaNode.h>
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
class MixerCore;
|
class MixerCore;
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ MixerOutput::GetOutputChannelDesignation(int channel)
|
|||||||
void
|
void
|
||||||
MixerOutput::SetOutputChannelGain(int channel, float gain)
|
MixerOutput::SetOutputChannelGain(int channel, float gain)
|
||||||
{
|
{
|
||||||
|
TRACE("SetOutputChannelGain chan %d, gain %.5f\n", channel, gain);
|
||||||
if (channel < 0 || channel >= fOutputChannelCount)
|
if (channel < 0 || channel >= fOutputChannelCount)
|
||||||
return;
|
return;
|
||||||
fOutputChannelInfo[channel].gain = gain;
|
fOutputChannelInfo[channel].gain = gain;
|
||||||
|
|||||||
@@ -4,8 +4,12 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "MixerUtils.h"
|
#include "MixerUtils.h"
|
||||||
|
#include "MixerInput.h"
|
||||||
|
#include "MixerOutput.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
const char *StringForFormat(const media_format & format, int index);
|
||||||
|
|
||||||
void
|
void
|
||||||
string_for_channel_mask(char *str, uint32 mask)
|
string_for_channel_mask(char *str, uint32 mask)
|
||||||
{
|
{
|
||||||
@@ -235,3 +239,53 @@ s_to_us(double secs)
|
|||||||
{
|
{
|
||||||
return (bigtime_t) (secs * 1000000.0);
|
return (bigtime_t) (secs * 1000000.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *StringForFormat(const media_format & format, int index)
|
||||||
|
{
|
||||||
|
static char str[2][50];
|
||||||
|
static char fmtstr[2][40];
|
||||||
|
const char *fmt;
|
||||||
|
switch (format.u.raw_audio.format) {
|
||||||
|
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||||
|
fmt = "float";
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_INT:
|
||||||
|
if (format.u.raw_audio.valid_bits != 0) {
|
||||||
|
sprintf(fmtstr[index & 1], "%d bit", format.u.raw_audio.valid_bits);
|
||||||
|
fmt = fmtstr[index & 1];
|
||||||
|
} else {
|
||||||
|
fmt = "32 bit";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||||
|
fmt = "16 bit";
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||||
|
fmt = "8 bit";
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||||
|
fmt = "8 bit unsigned";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fmt = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int a,b;
|
||||||
|
a = int(format.u.raw_audio.frame_rate + 0.05) / 1000;
|
||||||
|
b = int(format.u.raw_audio.frame_rate + 0.05) % 1000;
|
||||||
|
if (b)
|
||||||
|
sprintf(str[index & 1], "%d.%d kHz %s", a, b / 100, fmt);
|
||||||
|
else
|
||||||
|
sprintf(str[index & 1], "%d kHz %s", a, fmt);
|
||||||
|
return str[index & 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *StringForFormat(MixerOutput *output)
|
||||||
|
{
|
||||||
|
return StringForFormat(output->MediaOutput().format, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *StringForFormat(MixerInput *input)
|
||||||
|
{
|
||||||
|
return StringForFormat(input->MediaInput().format, 1);
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,4 +34,10 @@ uint32 ChannelTypeToChannelMask(int type);
|
|||||||
double us_to_s(bigtime_t usecs);
|
double us_to_s(bigtime_t usecs);
|
||||||
bigtime_t s_to_us(double secs);
|
bigtime_t s_to_us(double secs);
|
||||||
|
|
||||||
|
class MixerInput;
|
||||||
|
class MixerOutput;
|
||||||
|
|
||||||
|
const char *StringForFormat(MixerOutput *output); // not thread save
|
||||||
|
const char *StringForFormat(MixerInput *input); // not thread save
|
||||||
|
|
||||||
#endif //_MIXER_UTILS_H
|
#endif //_MIXER_UTILS_H
|
||||||
|
|||||||
Reference in New Issue
Block a user