Added support for setting the output frequency. Also done some preparation for
setting the input frequency, but I'm too lazy and not interested in the feature to actually implement it. For some reason the setting is not persistent. But the other parameters don't seem to be persistent either, so this is apparently a general problem. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34630 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
ec1dcae8cd
commit
d473f5766f
@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons media media-add-ons multi_audio ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
UsePrivateHeaders media ;
|
||||
UsePrivateHeaders media shared ;
|
||||
|
||||
if ! $(TARGET_PLATFORM_HAIKU_COMPATIBLE) {
|
||||
SubDirC++Flags -fmultiple-symbol-spaces ;
|
||||
|
@ -45,6 +45,75 @@ MultiAudioDevice::InitCheck() const
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MultiAudioDevice::BufferExchange(multi_buffer_info *info)
|
||||
{
|
||||
return buffer_exchange(fDevice, info);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MultiAudioDevice::SetMix(multi_mix_value_info *info)
|
||||
{
|
||||
return set_mix(fDevice, info);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MultiAudioDevice::GetMix(multi_mix_value_info *info)
|
||||
{
|
||||
return get_mix(fDevice, info);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MultiAudioDevice::SetInputFrameRate(uint32 multiAudioRate)
|
||||
{
|
||||
if ((fDescription.input_rates & multiAudioRate) == 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (fFormatInfo.input.rate == multiAudioRate)
|
||||
return B_OK;
|
||||
|
||||
uint32 oldRate = fFormatInfo.input.rate;
|
||||
fFormatInfo.input.rate = multiAudioRate;
|
||||
|
||||
status_t status = set_global_format(fDevice, &fFormatInfo);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n",
|
||||
strerror(status));
|
||||
fFormatInfo.input.rate = oldRate;
|
||||
return status;
|
||||
}
|
||||
|
||||
return _GetBuffers();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MultiAudioDevice::SetOutputFrameRate(uint32 multiAudioRate)
|
||||
{
|
||||
if ((fDescription.output_rates & multiAudioRate) == 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (fFormatInfo.output.rate == multiAudioRate)
|
||||
return B_OK;
|
||||
|
||||
uint32 oldRate = fFormatInfo.output.rate;
|
||||
fFormatInfo.output.rate = multiAudioRate;
|
||||
|
||||
status_t status = set_global_format(fDevice, &fFormatInfo);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n",
|
||||
strerror(status));
|
||||
fFormatInfo.output.rate = oldRate;
|
||||
return status;
|
||||
}
|
||||
|
||||
return _GetBuffers();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MultiAudioDevice::_InitDriver()
|
||||
{
|
||||
@ -154,7 +223,29 @@ MultiAudioDevice::_InitDriver()
|
||||
}
|
||||
|
||||
// Get the buffers
|
||||
status = _GetBuffers();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
|
||||
fMixControlInfo.info_size = sizeof(fMixControlInfo);
|
||||
fMixControlInfo.control_count = MAX_CONTROLS;
|
||||
fMixControlInfo.controls = fMixControl;
|
||||
|
||||
status = list_mix_controls(fDevice, &fMixControlInfo);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr, "Failed on DRIVER_LIST_MIX_CONTROLS: %s\n",
|
||||
strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MultiAudioDevice::_GetBuffers()
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_BUFFERS; i++) {
|
||||
fPlayBuffers[i] = &fPlayBufferList[i * MAX_CHANNELS];
|
||||
fRecordBuffers[i] = &fRecordBufferList[i * MAX_CHANNELS];
|
||||
@ -163,15 +254,15 @@ MultiAudioDevice::_InitDriver()
|
||||
fBufferList.request_playback_buffer_size = 0;
|
||||
// use the default...
|
||||
fBufferList.request_playback_buffers = MAX_BUFFERS;
|
||||
fBufferList.request_playback_channels = num_outputs;
|
||||
fBufferList.request_playback_channels = fDescription.output_channel_count;
|
||||
fBufferList.playback_buffers = (buffer_desc **) fPlayBuffers;
|
||||
fBufferList.request_record_buffer_size = 0;
|
||||
// use the default...
|
||||
fBufferList.request_record_buffers = MAX_BUFFERS;
|
||||
fBufferList.request_record_channels = num_inputs;
|
||||
fBufferList.request_record_channels = fDescription.input_channel_count;
|
||||
fBufferList.record_buffers = /*(buffer_desc **)*/ fRecordBuffers;
|
||||
|
||||
status = get_buffers(fDevice, &fBufferList);
|
||||
status_t status = get_buffers(fDevice, &fBufferList);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr, "Failed on B_MULTI_GET_BUFFERS: %s\n",
|
||||
strerror(status));
|
||||
@ -196,37 +287,5 @@ MultiAudioDevice::_InitDriver()
|
||||
}
|
||||
}
|
||||
|
||||
fMixControlInfo.info_size = sizeof(fMixControlInfo);
|
||||
fMixControlInfo.control_count = MAX_CONTROLS;
|
||||
fMixControlInfo.controls = fMixControl;
|
||||
|
||||
status = list_mix_controls(fDevice, &fMixControlInfo);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr, "Failed on DRIVER_LIST_MIX_CONTROLS: %s\n",
|
||||
strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MultiAudioDevice::BufferExchange(multi_buffer_info *info)
|
||||
{
|
||||
return buffer_exchange(fDevice, info);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MultiAudioDevice::SetMix(multi_mix_value_info *info)
|
||||
{
|
||||
return set_mix(fDevice, info);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MultiAudioDevice::GetMix(multi_mix_value_info *info)
|
||||
{
|
||||
return get_mix(fDevice, info);
|
||||
}
|
||||
|
@ -31,9 +31,14 @@ public:
|
||||
status_t SetMix(multi_mix_value_info* mixValueInfo);
|
||||
status_t GetMix(multi_mix_value_info* mixValueInfo);
|
||||
|
||||
status_t SetInputFrameRate(uint32 multiAudioRate);
|
||||
status_t SetOutputFrameRate(uint32 multiAudioRate);
|
||||
|
||||
private:
|
||||
status_t _InitDriver();
|
||||
status_t _GetBuffers();
|
||||
|
||||
private:
|
||||
status_t fInitStatus;
|
||||
int fDevice;
|
||||
char fPath[B_PATH_NAME_LENGTH];
|
||||
|
@ -5,14 +5,19 @@
|
||||
|
||||
//! Multi-audio replacement media addon for BeOS
|
||||
|
||||
|
||||
#include "MultiAudioNode.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Autolock.h>
|
||||
#include <Buffer.h>
|
||||
#include <BufferGroup.h>
|
||||
#include <ParameterWeb.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "MultiAudioUtility.h"
|
||||
#ifdef DEBUG
|
||||
@ -20,6 +25,11 @@
|
||||
#endif
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#define PARAMETER_ID_INPUT_FREQUENCY 1
|
||||
#define PARAMETER_ID_OUTPUT_FREQUENCY 2
|
||||
|
||||
|
||||
class node_input {
|
||||
public:
|
||||
node_input(media_input& input, media_format format);
|
||||
@ -52,6 +62,37 @@ public:
|
||||
};
|
||||
|
||||
|
||||
struct OutputFrameRateChangeCookie : public BReferenceable {
|
||||
float oldFrameRate;
|
||||
};
|
||||
|
||||
|
||||
struct sample_rate_info {
|
||||
uint32 multiAudioRate;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
static const sample_rate_info kSampleRateInfos[] = {
|
||||
{B_SR_8000, "8000"},
|
||||
{B_SR_11025, "11025"},
|
||||
{B_SR_12000, "12000"},
|
||||
{B_SR_16000, "16000"},
|
||||
{B_SR_22050, "22050"},
|
||||
{B_SR_24000, "24000"},
|
||||
{B_SR_32000, "32000"},
|
||||
{B_SR_44100, "44100"},
|
||||
{B_SR_48000, "48000"},
|
||||
{B_SR_64000, "64000"},
|
||||
{B_SR_88200, "88200"},
|
||||
{B_SR_96000, "96000"},
|
||||
{B_SR_176400, "176400"},
|
||||
{B_SR_192000, "192000"},
|
||||
{B_SR_384000, "384000"},
|
||||
{B_SR_1536000, "1536000"},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
const char* kMultiControlString[] = {
|
||||
"NAME IS ATTACHED",
|
||||
"Output", "Input", "Setup", "Tone Control", "Extended Setup", "Enhanced Setup", "Master",
|
||||
@ -61,6 +102,9 @@ const char* kMultiControlString[] = {
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
node_input::node_input(media_input& input, media_format format)
|
||||
{
|
||||
CALLED();
|
||||
@ -105,6 +149,7 @@ MultiAudioNode::MultiAudioNode(BMediaAddOn* addon, const char* name,
|
||||
MultiAudioDevice* device, int32 internalID, BMessage* config)
|
||||
: BMediaNode(name), BBufferConsumer(B_MEDIA_RAW_AUDIO),
|
||||
BBufferProducer(B_MEDIA_RAW_AUDIO),
|
||||
fBufferLock("multi audio buffers"),
|
||||
fThread(-1),
|
||||
fDevice(device),
|
||||
fTimeSourceStarted(false),
|
||||
@ -181,6 +226,52 @@ MultiAudioNode::InitCheck() const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MultiAudioNode::GetFlavor(flavor_info* info, int32 id)
|
||||
{
|
||||
CALLED();
|
||||
if (info == NULL)
|
||||
return;
|
||||
|
||||
info->flavor_flags = 0;
|
||||
info->possible_count = 1; // one flavor at a time
|
||||
info->in_format_count = 0; // no inputs
|
||||
info->in_formats = 0;
|
||||
info->out_format_count = 0; // no outputs
|
||||
info->out_formats = 0;
|
||||
info->internal_id = id;
|
||||
|
||||
info->name = (char*)"MultiAudioNode Node";
|
||||
info->info = (char*)"The MultiAudioNode node outputs to multi_audio "
|
||||
"drivers.";
|
||||
info->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER | B_TIME_SOURCE
|
||||
| B_PHYSICAL_OUTPUT | B_PHYSICAL_INPUT | B_CONTROLLABLE;
|
||||
info->in_format_count = 1; // 1 input
|
||||
media_format* inFormats = new media_format[info->in_format_count];
|
||||
GetFormat(&inFormats[0]);
|
||||
info->in_formats = inFormats;
|
||||
|
||||
info->out_format_count = 1; // 1 output
|
||||
media_format* outFormats = new media_format[info->out_format_count];
|
||||
GetFormat(&outFormats[0]);
|
||||
info->out_formats = outFormats;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MultiAudioNode::GetFormat(media_format* format)
|
||||
{
|
||||
CALLED();
|
||||
if (format == NULL)
|
||||
return;
|
||||
|
||||
format->type = B_MEDIA_RAW_AUDIO;
|
||||
format->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
|
||||
format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
|
||||
format->u.raw_audio = media_raw_audio_format::wildcard;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------- //
|
||||
// implementation of BMediaNode
|
||||
// -------------------------------------------------------- //
|
||||
@ -344,6 +435,25 @@ status_t
|
||||
MultiAudioNode::RequestCompleted(const media_request_info& info)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
if (info.what != media_request_info::B_REQUEST_FORMAT_CHANGE)
|
||||
return B_OK;
|
||||
|
||||
OutputFrameRateChangeCookie* cookie
|
||||
= (OutputFrameRateChangeCookie*)info.user_data;
|
||||
if (cookie == NULL)
|
||||
return B_OK;
|
||||
|
||||
BReference<OutputFrameRateChangeCookie> cookieReference(cookie, true);
|
||||
|
||||
// if the request failed, we reset the frame rate
|
||||
if (info.status != B_OK) {
|
||||
_SetNodeInputFrameRate(cookie->oldFrameRate);
|
||||
|
||||
// TODO: If we have multiple connections, we should request to change
|
||||
// the format back!
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -529,15 +639,7 @@ MultiAudioNode::Connected(const media_source& producer,
|
||||
return B_MEDIA_BAD_DESTINATION;
|
||||
}
|
||||
|
||||
// use one buffer length latency
|
||||
fInternalLatency = with_format.u.raw_audio.buffer_size * 10000 / 2
|
||||
/ ( (with_format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
|
||||
* with_format.u.raw_audio.channel_count)
|
||||
/ ((int32)(with_format.u.raw_audio.frame_rate / 100));
|
||||
|
||||
PRINT((" internal latency = %lld\n",fInternalLatency));
|
||||
|
||||
SetEventLatency(fInternalLatency);
|
||||
_UpdateInternalLatency(with_format);
|
||||
|
||||
// record the agreed upon values
|
||||
channel->fInput.source = producer;
|
||||
@ -563,6 +665,8 @@ MultiAudioNode::Disconnected(const media_source& producer,
|
||||
|
||||
channel->fInput.source = media_source::null;
|
||||
channel->fInput.format = channel->fPreferredFormat;
|
||||
|
||||
BAutolock locker(fBufferLock);
|
||||
_FillWithZeros(*channel);
|
||||
//GetFormat(&channel->fInput.format);
|
||||
}
|
||||
@ -1201,6 +1305,20 @@ MultiAudioNode::GetParameterValue(int32 id, bigtime_t* lastChange, void* value,
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (id == PARAMETER_ID_INPUT_FREQUENCY
|
||||
|| id == PARAMETER_ID_OUTPUT_FREQUENCY) {
|
||||
const multi_format_info& info = fDevice->FormatInfo();
|
||||
uint32 rate = id == PARAMETER_ID_INPUT_FREQUENCY
|
||||
? info.input.rate : info.output.rate;
|
||||
|
||||
if (*size < sizeof(rate))
|
||||
return B_ERROR;
|
||||
|
||||
memcpy(value, &rate, sizeof(rate));
|
||||
*size = sizeof(rate);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
multi_mix_value_info info;
|
||||
multi_mix_value values[2];
|
||||
info.values = values;
|
||||
@ -1279,6 +1397,58 @@ MultiAudioNode::SetParameterValue(int32 id, bigtime_t performanceTime,
|
||||
if (parameter == NULL)
|
||||
return;
|
||||
|
||||
if (id == PARAMETER_ID_INPUT_FREQUENCY) {
|
||||
// TODO: Support!
|
||||
return;
|
||||
}
|
||||
|
||||
if (id == PARAMETER_ID_OUTPUT_FREQUENCY) {
|
||||
uint32 rate;
|
||||
if (size < sizeof(rate))
|
||||
return;
|
||||
memcpy(&rate, value, sizeof(rate));
|
||||
|
||||
// create a cookie RequestCompleted() can get the old frame rate from,
|
||||
// if anything goes wrong
|
||||
OutputFrameRateChangeCookie* cookie
|
||||
= new(std::nothrow) OutputFrameRateChangeCookie;
|
||||
if (cookie == NULL)
|
||||
return;
|
||||
|
||||
cookie->oldFrameRate = fOutputPreferredFormat.u.raw_audio.frame_rate;
|
||||
BReference<OutputFrameRateChangeCookie> cookieReference(cookie, true);
|
||||
|
||||
// NOTE: What we should do is call RequestFormatChange() for all
|
||||
// connections and change the device's format in RequestCompleted().
|
||||
// Unfortunately we need the new buffer size first, which we only get
|
||||
// from the device after changing the format. So we do that now and
|
||||
// reset it in RequestCompleted(), if something went wrong. This causes
|
||||
// the buffers we receive until then to be played incorrectly leading
|
||||
// to unpleasant noise.
|
||||
float frameRate = MultiAudio::convert_to_sample_rate(rate);
|
||||
if (_SetNodeInputFrameRate(frameRate) != B_OK)
|
||||
return;
|
||||
|
||||
for (int32 i = 0; i < fInputs.CountItems(); i++) {
|
||||
node_input* channel = (node_input*)fInputs.ItemAt(i);
|
||||
if (channel->fInput.source == media_source::null)
|
||||
continue;
|
||||
|
||||
media_format newFormat = channel->fInput.format;
|
||||
newFormat.u.raw_audio.frame_rate = frameRate;
|
||||
newFormat.u.raw_audio.buffer_size
|
||||
= fOutputPreferredFormat.u.raw_audio.buffer_size;
|
||||
|
||||
int32 changeTag = 0;
|
||||
status_t error = RequestFormatChange(channel->fInput.source,
|
||||
channel->fInput.destination, newFormat, NULL, &changeTag);
|
||||
if (error == B_OK)
|
||||
cookie->AcquireReference();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
multi_mix_value_info info;
|
||||
multi_mix_value values[2];
|
||||
info.values = values;
|
||||
@ -1333,6 +1503,15 @@ MultiAudioNode::MakeParameterWeb()
|
||||
PRINT(("MixControlInfo().control_count : %li\n",
|
||||
fDevice->MixControlInfo().control_count));
|
||||
|
||||
BParameterGroup* generalGroup = web->MakeGroup("General");
|
||||
|
||||
const multi_description& description = fDevice->Description();
|
||||
// _CreateFrequencyParameterGroup(generalGroup, "Input",
|
||||
// PARAMETER_ID_INPUT_FREQUENCY, description.input_rates);
|
||||
// TODO: Enable when implemented correctly in SetParameterValue()!
|
||||
_CreateFrequencyParameterGroup(generalGroup, "Output",
|
||||
PARAMETER_ID_OUTPUT_FREQUENCY, description.output_rates);
|
||||
|
||||
multi_mix_control* controls = fDevice->MixControlInfo().controls;
|
||||
|
||||
for (int i = 0; i < fDevice->MixControlInfo().control_count; i++) {
|
||||
@ -1453,6 +1632,25 @@ MultiAudioNode::_ProcessMux(BDiscreteParameter* parameter, int32 index)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MultiAudioNode::_CreateFrequencyParameterGroup(BParameterGroup* parentGroup,
|
||||
const char* name, int32 parameterID, uint32 rateMask)
|
||||
{
|
||||
BParameterGroup* group = parentGroup->MakeGroup(name);
|
||||
BDiscreteParameter* frequencyParam = group->MakeDiscreteParameter(
|
||||
parameterID, B_MEDIA_NO_TYPE, BString(name) << " Frequency:",
|
||||
B_GENERIC);
|
||||
|
||||
for (int32 i = 0; kSampleRateInfos[i].name != NULL; i++) {
|
||||
const sample_rate_info& info = kSampleRateInfos[i];
|
||||
if ((rateMask & info.multiAudioRate) != 0) {
|
||||
frequencyParam->AddItem(info.multiAudioRate,
|
||||
BString(info.name) << " kHz");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - MultiAudioNode specific functions
|
||||
|
||||
|
||||
@ -1467,12 +1665,18 @@ MultiAudioNode::_RunThread()
|
||||
bufferInfo.playback_buffer_cycle = 0;
|
||||
bufferInfo.record_buffer_cycle = 0;
|
||||
|
||||
// reset the info for the performance time computation
|
||||
fResetPerformanceTimeBase = true;
|
||||
|
||||
while (true) {
|
||||
// TODO: why this semaphore??
|
||||
if (acquire_sem_etc(fBufferFreeSem, 1, B_RELATIVE_TIMEOUT, 0)
|
||||
== B_BAD_SEM_ID)
|
||||
return B_OK;
|
||||
|
||||
BAutolock locker(fBufferLock);
|
||||
// make sure the buffers don't change while we're playing with them
|
||||
|
||||
// send buffer
|
||||
fDevice->BufferExchange(&bufferInfo);
|
||||
|
||||
@ -1924,11 +2128,23 @@ MultiAudioNode::_UpdateTimeSource(multi_buffer_info& info,
|
||||
if (!fTimeSourceStarted || oldInfo.played_real_time == 0)
|
||||
return;
|
||||
|
||||
bigtime_t performanceTime = (bigtime_t)(info.played_frames_count /
|
||||
input.fInput.format.u.raw_audio.frame_rate * 1000000LL);
|
||||
if (fResetPerformanceTimeBase) {
|
||||
fPerformanceTimeBase = info.played_real_time;
|
||||
fPerformanceTimeBaseFrames = info.played_frames_count;
|
||||
fResetPerformanceTimeBase = false;
|
||||
return;
|
||||
}
|
||||
|
||||
double usecsPerFrame = 1000000 / input.fInput.format.u.raw_audio.frame_rate;
|
||||
uint64 frameCount = info.played_frames_count
|
||||
- fPerformanceTimeBaseFrames;
|
||||
uint64 oldFrameCount = oldInfo.played_frames_count
|
||||
- fPerformanceTimeBaseFrames;
|
||||
|
||||
bigtime_t performanceTime = (bigtime_t)(frameCount * usecsPerFrame)
|
||||
+ fPerformanceTimeBase;
|
||||
bigtime_t realTime = info.played_real_time;
|
||||
float drift = ((info.played_frames_count - oldInfo.played_frames_count)
|
||||
/ input.fInput.format.u.raw_audio.frame_rate * 1000000LL)
|
||||
float drift = ((frameCount - oldFrameCount) * usecsPerFrame)
|
||||
/ (info.played_real_time - oldInfo.played_real_time);
|
||||
|
||||
PublishTime(performanceTime, realTime, drift);
|
||||
@ -2092,47 +2308,69 @@ MultiAudioNode::_run_thread_(void* data)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MultiAudioNode::GetFlavor(flavor_info* info, int32 id)
|
||||
status_t
|
||||
MultiAudioNode::_SetNodeInputFrameRate(float frameRate)
|
||||
{
|
||||
CALLED();
|
||||
if (info == NULL)
|
||||
return;
|
||||
// check whether the frame rate is supported
|
||||
uint32 multiAudioRate = MultiAudio::convert_from_sample_rate(frameRate);
|
||||
if ((fDevice->Description().output_rates & multiAudioRate) == 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
info->flavor_flags = 0;
|
||||
info->possible_count = 1; // one flavor at a time
|
||||
info->in_format_count = 0; // no inputs
|
||||
info->in_formats = 0;
|
||||
info->out_format_count = 0; // no outputs
|
||||
info->out_formats = 0;
|
||||
info->internal_id = id;
|
||||
BAutolock locker(fBufferLock);
|
||||
|
||||
info->name = "MultiAudioNode Node";
|
||||
info->info = "The MultiAudioNode node outputs to multi_audio drivers.";
|
||||
info->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER | B_TIME_SOURCE
|
||||
| B_PHYSICAL_OUTPUT | B_PHYSICAL_INPUT | B_CONTROLLABLE;
|
||||
info->in_format_count = 1; // 1 input
|
||||
media_format* inFormats = new media_format[info->in_format_count];
|
||||
GetFormat(&inFormats[0]);
|
||||
info->in_formats = inFormats;
|
||||
// already set?
|
||||
if (fDevice->FormatInfo().output.rate == multiAudioRate)
|
||||
return B_OK;
|
||||
|
||||
info->out_format_count = 1; // 1 output
|
||||
media_format* outFormats = new media_format[info->out_format_count];
|
||||
GetFormat(&outFormats[0]);
|
||||
info->out_formats = outFormats;
|
||||
// set the frame rate on the device
|
||||
status_t error = fDevice->SetOutputFrameRate(multiAudioRate);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// it went fine -- update all formats
|
||||
fOutputPreferredFormat.u.raw_audio.frame_rate = frameRate;
|
||||
fOutputPreferredFormat.u.raw_audio.buffer_size
|
||||
= fDevice->BufferList().return_playback_buffer_size
|
||||
* (fOutputPreferredFormat.u.raw_audio.format
|
||||
& media_raw_audio_format::B_AUDIO_SIZE_MASK)
|
||||
* fOutputPreferredFormat.u.raw_audio.channel_count;
|
||||
|
||||
for (int32 i = 0; node_input* channel = (node_input*)fInputs.ItemAt(i);
|
||||
i++) {
|
||||
channel->fPreferredFormat.u.raw_audio.frame_rate = frameRate;
|
||||
channel->fPreferredFormat.u.raw_audio.buffer_size
|
||||
= fOutputPreferredFormat.u.raw_audio.buffer_size;
|
||||
|
||||
channel->fFormat.u.raw_audio.frame_rate = frameRate;
|
||||
channel->fFormat.u.raw_audio.buffer_size
|
||||
= fOutputPreferredFormat.u.raw_audio.buffer_size;
|
||||
|
||||
channel->fInput.format.u.raw_audio.frame_rate = frameRate;
|
||||
channel->fInput.format.u.raw_audio.buffer_size
|
||||
= fOutputPreferredFormat.u.raw_audio.buffer_size;
|
||||
}
|
||||
|
||||
// make sure the time base is reset
|
||||
fResetPerformanceTimeBase = true;
|
||||
|
||||
// update internal latency
|
||||
_UpdateInternalLatency(fOutputPreferredFormat);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MultiAudioNode::GetFormat(media_format* format)
|
||||
MultiAudioNode::_UpdateInternalLatency(const media_format& format)
|
||||
{
|
||||
CALLED();
|
||||
if (format == NULL)
|
||||
return;
|
||||
// use one buffer length latency
|
||||
fInternalLatency = format.u.raw_audio.buffer_size * 10000 / 2
|
||||
/ ((format.u.raw_audio.format
|
||||
& media_raw_audio_format::B_AUDIO_SIZE_MASK)
|
||||
* format.u.raw_audio.channel_count)
|
||||
/ ((int32)(format.u.raw_audio.frame_rate / 100));
|
||||
|
||||
format->type = B_MEDIA_RAW_AUDIO;
|
||||
format->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
|
||||
format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
|
||||
format->u.raw_audio = media_raw_audio_format::wildcard;
|
||||
PRINT((" internal latency = %lld\n",fInternalLatency));
|
||||
|
||||
SetEventLatency(fInternalLatency);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <BufferConsumer.h>
|
||||
#include <BufferProducer.h>
|
||||
#include <Controllable.h>
|
||||
#include <Locker.h>
|
||||
#include <MediaAddOn.h>
|
||||
#include <MediaDefs.h>
|
||||
#include <MediaEventLooper.h>
|
||||
@ -188,6 +189,12 @@ private:
|
||||
int32& numParameters);
|
||||
void _ProcessMux(BDiscreteParameter* parameter,
|
||||
int32 index);
|
||||
void _CreateFrequencyParameterGroup(
|
||||
BParameterGroup* parentGroup, const char* name,
|
||||
int32 parameterID, uint32 rateMask);
|
||||
|
||||
status_t _SetNodeInputFrameRate(float frameRate);
|
||||
void _UpdateInternalLatency(const media_format& format);
|
||||
|
||||
private:
|
||||
status_t fInitStatus;
|
||||
@ -195,7 +202,12 @@ private:
|
||||
BMediaAddOn* fAddOn;
|
||||
int32 fId;
|
||||
|
||||
BLocker fBufferLock;
|
||||
|
||||
BList fInputs;
|
||||
bool fResetPerformanceTimeBase;
|
||||
bigtime_t fPerformanceTimeBase;
|
||||
uint64 fPerformanceTimeBaseFrames;
|
||||
|
||||
bigtime_t fLatency;
|
||||
BList fOutputs;
|
||||
|
Loading…
Reference in New Issue
Block a user