multi_audio: Add support for input/output framerate change

Signed-off-by: Jérôme Duval <[email protected]>
This commit is contained in:
Jerome Leveque
2012-02-28 21:39:03 +01:00
committed by Jérôme Duval
parent fc581f23c9
commit eaa6a6c40c
2 changed files with 140 additions and 22 deletions
@@ -44,6 +44,7 @@ public:
BBuffer* fBuffer;
};
class node_output {
public:
node_output(media_output& output, media_format format);
@@ -62,8 +63,9 @@ public:
};
struct OutputFrameRateChangeCookie : public BReferenceable {
struct FrameRateChangeCookie : public BReferenceable {
float oldFrameRate;
uint32 id;
};
@@ -72,6 +74,7 @@ struct sample_rate_info {
const char* name;
};
static const sample_rate_info kSampleRateInfos[] = {
{B_SR_8000, "8000"},
{B_SR_11025, "11025"},
@@ -438,16 +441,21 @@ MultiAudioNode::RequestCompleted(const media_request_info& info)
if (info.what != media_request_info::B_REQUEST_FORMAT_CHANGE)
return B_OK;
OutputFrameRateChangeCookie* cookie
= (OutputFrameRateChangeCookie*)info.user_data;
FrameRateChangeCookie* cookie
= (FrameRateChangeCookie*)info.user_data;
if (cookie == NULL)
return B_OK;
BReference<OutputFrameRateChangeCookie> cookieReference(cookie, true);
BReference<FrameRateChangeCookie> cookieReference(cookie, true);
// if the request failed, we reset the frame rate
if (info.status != B_OK) {
_SetNodeInputFrameRate(cookie->oldFrameRate);
if (cookie->id == PARAMETER_ID_INPUT_FREQUENCY) {
_SetNodeInputFrameRate(cookie->oldFrameRate);
if (fDevice->Description().output_rates & B_SR_SAME_AS_INPUT)
_SetNodeOutputFrameRate(cookie->oldFrameRate);
} else if (cookie->id == PARAMETER_ID_OUTPUT_FREQUENCY)
_SetNodeOutputFrameRate(cookie->oldFrameRate);
// TODO: If we have multiple connections, we should request to change
// the format back!
@@ -503,10 +511,10 @@ MultiAudioNode::AcceptFormat(const media_destination& dest,
format->u.raw_audio.format = channel->fPreferredFormat.u.raw_audio.format;
format->u.raw_audio.valid_bits = channel->fPreferredFormat.u.raw_audio.valid_bits;
format->u.raw_audio.frame_rate = channel->fPreferredFormat.u.raw_audio.frame_rate;
format->u.raw_audio.frame_rate = channel->fPreferredFormat.u.raw_audio.frame_rate;
format->u.raw_audio.channel_count = channel->fPreferredFormat.u.raw_audio.channel_count;
format->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
format->u.raw_audio.buffer_size = fDevice->BufferList().return_playback_buffer_size
format->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
format->u.raw_audio.buffer_size = fDevice->BufferList().return_playback_buffer_size
* (format->u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
* format->u.raw_audio.channel_count;
@@ -1305,6 +1313,7 @@ MultiAudioNode::GetParameterValue(int32 id, bigtime_t* lastChange, void* value,
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;
@@ -1394,12 +1403,9 @@ 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) {
if (id == PARAMETER_ID_OUTPUT_FREQUENCY
|| (id == PARAMETER_ID_INPUT_FREQUENCY
&& (fDevice->Description().output_rates & B_SR_SAME_AS_INPUT))) {
uint32 rate;
if (size < sizeof(rate))
return;
@@ -1410,13 +1416,14 @@ MultiAudioNode::SetParameterValue(int32 id, bigtime_t performanceTime,
// create a cookie RequestCompleted() can get the old frame rate from,
// if anything goes wrong
OutputFrameRateChangeCookie* cookie
= new(std::nothrow) OutputFrameRateChangeCookie;
FrameRateChangeCookie* cookie
= new(std::nothrow) FrameRateChangeCookie;
if (cookie == NULL)
return;
cookie->oldFrameRate = fOutputPreferredFormat.u.raw_audio.frame_rate;
BReference<OutputFrameRateChangeCookie> cookieReference(cookie, true);
cookie->id = id;
BReference<FrameRateChangeCookie> cookieReference(cookie, true);
// NOTE: What we should do is call RequestFormatChange() for all
// connections and change the device's format in RequestCompleted().
@@ -1446,6 +1453,59 @@ MultiAudioNode::SetParameterValue(int32 id, bigtime_t performanceTime,
cookie->AcquireReference();
}
if (id != PARAMETER_ID_INPUT_FREQUENCY)
return;
//Do not return cause we should go in the next if
}
if (id == PARAMETER_ID_INPUT_FREQUENCY) {
uint32 rate;
if (size < sizeof(rate))
return;
memcpy(&rate, value, sizeof(rate));
if (rate == fInputPreferredFormat.u.raw_audio.frame_rate)
return;
// create a cookie RequestCompleted() can get the old frame rate from,
// if anything goes wrong
FrameRateChangeCookie* cookie
= new(std::nothrow) FrameRateChangeCookie;
if (cookie == NULL)
return;
cookie->oldFrameRate = fInputPreferredFormat.u.raw_audio.frame_rate;
cookie->id = id;
BReference<FrameRateChangeCookie> 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 (_SetNodeOutputFrameRate(frameRate) != B_OK)
return;
for (int32 i = 0; i < fOutputs.CountItems(); i++) {
node_output* channel = (node_output*)fOutputs.ItemAt(i);
if (channel->fOutput.source == media_source::null)
continue;
media_format newFormat = channel->fOutput.format;
newFormat.u.raw_audio.frame_rate = frameRate;
newFormat.u.raw_audio.buffer_size
= fInputPreferredFormat.u.raw_audio.buffer_size;
int32 changeTag = 0;
status_t error = RequestFormatChange(channel->fOutput.source,
channel->fOutput.destination, newFormat, NULL, &changeTag);
if (error == B_OK)
cookie->AcquireReference();
}
return;
}
@@ -1506,11 +1566,16 @@ MultiAudioNode::MakeParameterWeb()
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);
if (description.output_rates & B_SR_SAME_AS_INPUT) {
_CreateFrequencyParameterGroup(generalGroup, "Input & Output",
PARAMETER_ID_INPUT_FREQUENCY, description.input_rates);
} else {
_CreateFrequencyParameterGroup(generalGroup, "Input",
PARAMETER_ID_INPUT_FREQUENCY, description.input_rates);
_CreateFrequencyParameterGroup(generalGroup, "Output",
PARAMETER_ID_OUTPUT_FREQUENCY, description.output_rates);
}
multi_mix_control* controls = fDevice->MixControlInfo().controls;
@@ -2362,6 +2427,58 @@ MultiAudioNode::_SetNodeInputFrameRate(float frameRate)
}
status_t
MultiAudioNode::_SetNodeOutputFrameRate(float frameRate)
{
// check whether the frame rate is supported
uint32 multiAudioRate = MultiAudio::convert_from_sample_rate(frameRate);
if ((fDevice->Description().input_rates & multiAudioRate) == 0)
return B_BAD_VALUE;
BAutolock locker(fBufferLock);
// already set?
if (fDevice->FormatInfo().input.rate == multiAudioRate)
return B_OK;
// set the frame rate on the device
status_t error = fDevice->SetInputFrameRate(multiAudioRate);
if (error != B_OK)
return error;
// it went fine -- update all formats
fInputPreferredFormat.u.raw_audio.frame_rate = frameRate;
fInputPreferredFormat.u.raw_audio.buffer_size
= fDevice->BufferList().return_record_buffer_size
* (fInputPreferredFormat.u.raw_audio.format
& media_raw_audio_format::B_AUDIO_SIZE_MASK)
* fInputPreferredFormat.u.raw_audio.channel_count;
for (int32 i = 0; node_output* channel = (node_output*)fOutputs.ItemAt(i);
i++) {
channel->fPreferredFormat.u.raw_audio.frame_rate = frameRate;
channel->fPreferredFormat.u.raw_audio.buffer_size
= fInputPreferredFormat.u.raw_audio.buffer_size;
channel->fFormat.u.raw_audio.frame_rate = frameRate;
channel->fFormat.u.raw_audio.buffer_size
= fInputPreferredFormat.u.raw_audio.buffer_size;
channel->fOutput.format.u.raw_audio.frame_rate = frameRate;
channel->fOutput.format.u.raw_audio.buffer_size
= fInputPreferredFormat.u.raw_audio.buffer_size;
}
// make sure the time base is reset
fTimeComputer.SetFrameRate(frameRate);
// update internal latency
_UpdateInternalLatency(fInputPreferredFormat);
return B_OK;
}
void
MultiAudioNode::_UpdateInternalLatency(const media_format& format)
{
@@ -196,6 +196,7 @@ private:
int32 parameterID, uint32 rateMask);
status_t _SetNodeInputFrameRate(float frameRate);
status_t _SetNodeOutputFrameRate(float frameRate);
void _UpdateInternalLatency(const media_format& format);
private: