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; BBuffer* fBuffer;
}; };
class node_output { class node_output {
public: public:
node_output(media_output& output, media_format format); node_output(media_output& output, media_format format);
@@ -62,8 +63,9 @@ public:
}; };
struct OutputFrameRateChangeCookie : public BReferenceable { struct FrameRateChangeCookie : public BReferenceable {
float oldFrameRate; float oldFrameRate;
uint32 id;
}; };
@@ -72,6 +74,7 @@ struct sample_rate_info {
const char* name; const char* name;
}; };
static const sample_rate_info kSampleRateInfos[] = { static const sample_rate_info kSampleRateInfos[] = {
{B_SR_8000, "8000"}, {B_SR_8000, "8000"},
{B_SR_11025, "11025"}, {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) if (info.what != media_request_info::B_REQUEST_FORMAT_CHANGE)
return B_OK; return B_OK;
OutputFrameRateChangeCookie* cookie FrameRateChangeCookie* cookie
= (OutputFrameRateChangeCookie*)info.user_data; = (FrameRateChangeCookie*)info.user_data;
if (cookie == NULL) if (cookie == NULL)
return B_OK; return B_OK;
BReference<OutputFrameRateChangeCookie> cookieReference(cookie, true); BReference<FrameRateChangeCookie> cookieReference(cookie, true);
// if the request failed, we reset the frame rate // if the request failed, we reset the frame rate
if (info.status != B_OK) { 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 // TODO: If we have multiple connections, we should request to change
// the format back! // 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.format = channel->fPreferredFormat.u.raw_audio.format;
format->u.raw_audio.valid_bits = channel->fPreferredFormat.u.raw_audio.valid_bits; 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.channel_count = channel->fPreferredFormat.u.raw_audio.channel_count;
format->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; 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.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.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
* format->u.raw_audio.channel_count; * 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 if (id == PARAMETER_ID_INPUT_FREQUENCY
|| id == PARAMETER_ID_OUTPUT_FREQUENCY) { || id == PARAMETER_ID_OUTPUT_FREQUENCY) {
const multi_format_info& info = fDevice->FormatInfo(); const multi_format_info& info = fDevice->FormatInfo();
uint32 rate = id == PARAMETER_ID_INPUT_FREQUENCY uint32 rate = id == PARAMETER_ID_INPUT_FREQUENCY
? info.input.rate : info.output.rate; ? info.input.rate : info.output.rate;
@@ -1394,12 +1403,9 @@ MultiAudioNode::SetParameterValue(int32 id, bigtime_t performanceTime,
if (parameter == NULL) if (parameter == NULL)
return; return;
if (id == PARAMETER_ID_INPUT_FREQUENCY) { if (id == PARAMETER_ID_OUTPUT_FREQUENCY
// TODO: Support! || (id == PARAMETER_ID_INPUT_FREQUENCY
return; && (fDevice->Description().output_rates & B_SR_SAME_AS_INPUT))) {
}
if (id == PARAMETER_ID_OUTPUT_FREQUENCY) {
uint32 rate; uint32 rate;
if (size < sizeof(rate)) if (size < sizeof(rate))
return; return;
@@ -1410,13 +1416,14 @@ MultiAudioNode::SetParameterValue(int32 id, bigtime_t performanceTime,
// create a cookie RequestCompleted() can get the old frame rate from, // create a cookie RequestCompleted() can get the old frame rate from,
// if anything goes wrong // if anything goes wrong
OutputFrameRateChangeCookie* cookie FrameRateChangeCookie* cookie
= new(std::nothrow) OutputFrameRateChangeCookie; = new(std::nothrow) FrameRateChangeCookie;
if (cookie == NULL) if (cookie == NULL)
return; return;
cookie->oldFrameRate = fOutputPreferredFormat.u.raw_audio.frame_rate; 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 // NOTE: What we should do is call RequestFormatChange() for all
// connections and change the device's format in RequestCompleted(). // connections and change the device's format in RequestCompleted().
@@ -1446,6 +1453,59 @@ MultiAudioNode::SetParameterValue(int32 id, bigtime_t performanceTime,
cookie->AcquireReference(); 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; return;
} }
@@ -1506,11 +1566,16 @@ MultiAudioNode::MakeParameterWeb()
BParameterGroup* generalGroup = web->MakeGroup("General"); BParameterGroup* generalGroup = web->MakeGroup("General");
const multi_description& description = fDevice->Description(); const multi_description& description = fDevice->Description();
// _CreateFrequencyParameterGroup(generalGroup, "Input",
// PARAMETER_ID_INPUT_FREQUENCY, description.input_rates); if (description.output_rates & B_SR_SAME_AS_INPUT) {
// TODO: Enable when implemented correctly in SetParameterValue()! _CreateFrequencyParameterGroup(generalGroup, "Input & Output",
_CreateFrequencyParameterGroup(generalGroup, "Output", PARAMETER_ID_INPUT_FREQUENCY, description.input_rates);
PARAMETER_ID_OUTPUT_FREQUENCY, description.output_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; 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 void
MultiAudioNode::_UpdateInternalLatency(const media_format& format) MultiAudioNode::_UpdateInternalLatency(const media_format& format)
{ {
@@ -196,6 +196,7 @@ private:
int32 parameterID, uint32 rateMask); int32 parameterID, uint32 rateMask);
status_t _SetNodeInputFrameRate(float frameRate); status_t _SetNodeInputFrameRate(float frameRate);
status_t _SetNodeOutputFrameRate(float frameRate);
void _UpdateInternalLatency(const media_format& format); void _UpdateInternalLatency(const media_format& format);
private: private: