* Copyright (c) 1999-2000, Eric Moon.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions, and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "AudioAdapterNode.h"
#include "AudioAdapterParams.h"
#include "SoundUtils.h"
#include <cstdio>
#include <cstring>
_AudioAdapterNode::~_AudioAdapterNode() {}
_AudioAdapterNode::_AudioAdapterNode(
const char* name,
IAudioOpFactory* opFactory,
BMediaAddOn* addOn) :
BMediaNode(name),
AudioFilterNode(name, opFactory, addOn) {
}
status_t _AudioAdapterNode::getRequiredInputFormat(
media_format& ioFormat) {
status_t err = getPreferredInputFormat(ioFormat);
if(err < B_OK)
return err;
ioFormat.u.raw_audio.byte_order = media_raw_audio_format::wildcard.byte_order;
_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
ASSERT(p);
ioFormat.u.raw_audio.format = p->inputFormat.format;
ioFormat.u.raw_audio.channel_count = p->inputFormat.channel_count;
ioFormat.u.raw_audio.buffer_size = media_raw_audio_format::wildcard.buffer_size;
if(output().destination == media_destination::null) {
ioFormat.u.raw_audio.frame_rate = media_raw_audio_format::wildcard.frame_rate;
}
return B_OK;
}
status_t _AudioAdapterNode::getPreferredInputFormat(
media_format& ioFormat) {
status_t err = _inherited::getPreferredInputFormat(ioFormat);
if(err < B_OK)
return err;
_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
ASSERT(p);
media_raw_audio_format& f = ioFormat.u.raw_audio;
const media_raw_audio_format& w = media_raw_audio_format::wildcard;
if(p->inputFormat.format != w.format)
f.format = p->inputFormat.format;
if(p->inputFormat.channel_count != w.channel_count)
f.channel_count = p->inputFormat.channel_count;
if(output().destination != media_destination::null) {
if(f.format == w.format)
f.format = output().format.u.raw_audio.format;
if(f.channel_count == w.channel_count)
f.channel_count = output().format.u.raw_audio.channel_count;
f.buffer_size =
bytes_per_frame(f) *
frames_per_buffer(output().format.u.raw_audio);
f.frame_rate = output().format.u.raw_audio.frame_rate;
}
return B_OK;
}
status_t _AudioAdapterNode::getRequiredOutputFormat(
media_format& ioFormat) {
status_t err = getPreferredOutputFormat(ioFormat);
if(err < B_OK)
return err;
ioFormat.u.raw_audio.format = media_raw_audio_format::wildcard.format;
ioFormat.u.raw_audio.channel_count = media_raw_audio_format::wildcard.channel_count;
_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
ASSERT(p);
ioFormat.u.raw_audio.format = p->outputFormat.format;
ioFormat.u.raw_audio.channel_count = p->outputFormat.channel_count;
ioFormat.u.raw_audio.buffer_size = media_raw_audio_format::wildcard.buffer_size;
if(input().source == media_source::null) {
ioFormat.u.raw_audio.frame_rate = media_raw_audio_format::wildcard.frame_rate;
}
return B_OK;
}
status_t _AudioAdapterNode::getPreferredOutputFormat(
media_format& ioFormat) {
status_t err = _inherited::getPreferredOutputFormat(ioFormat);
if(err < B_OK)
return err;
_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
ASSERT(p);
const media_raw_audio_format& w = media_raw_audio_format::wildcard;
if(p->outputFormat.format != w.format)
ioFormat.u.raw_audio.format = p->outputFormat.format;
if(p->outputFormat.channel_count != w.channel_count)
ioFormat.u.raw_audio.channel_count = p->outputFormat.channel_count;
if(input().source != media_source::null) {
if(ioFormat.u.raw_audio.format == w.format)
ioFormat.u.raw_audio.format = input().format.u.raw_audio.format;
if(ioFormat.u.raw_audio.channel_count == w.channel_count)
ioFormat.u.raw_audio.channel_count = input().format.u.raw_audio.channel_count;
ioFormat.u.raw_audio.buffer_size =
bytes_per_frame(ioFormat.u.raw_audio) *
frames_per_buffer(input().format.u.raw_audio);
PRINT(("##### preferred output buffer_size: %ld (%" B_PRIxSIZE ")\n", ioFormat.u.raw_audio.buffer_size, ioFormat.u.raw_audio.buffer_size));
ioFormat.u.raw_audio.frame_rate = input().format.u.raw_audio.frame_rate;
}
return B_OK;
}
status_t _AudioAdapterNode::validateProposedInputFormat(
const media_format& preferredFormat,
media_format& ioProposedFormat) {
status_t err = _inherited::validateProposedInputFormat(
preferredFormat, ioProposedFormat);
const media_raw_audio_format& w = media_raw_audio_format::wildcard;
if(output().destination != media_destination::null) {
if(
ioProposedFormat.u.raw_audio.format != w.format &&
ioProposedFormat.u.raw_audio.channel_count != w.channel_count) {
size_t target_buffer_size =
bytes_per_frame(ioProposedFormat.u.raw_audio) *
frames_per_buffer(output().format.u.raw_audio);
if(ioProposedFormat.u.raw_audio.buffer_size != target_buffer_size) {
if(ioProposedFormat.u.raw_audio.buffer_size != w.buffer_size)
err = B_MEDIA_BAD_FORMAT;
ioProposedFormat.u.raw_audio.buffer_size = target_buffer_size;
}
}
if(ioProposedFormat.u.raw_audio.frame_rate != output().format.u.raw_audio.frame_rate) {
if(ioProposedFormat.u.raw_audio.frame_rate != w.frame_rate)
err = B_MEDIA_BAD_FORMAT;
ioProposedFormat.u.raw_audio.frame_rate = output().format.u.raw_audio.frame_rate;
}
}
char fmt_string[256];
string_for_format(ioProposedFormat, fmt_string, 255);
PRINT((
"### _AudioAdapterNode::validateProposedInputFormat():\n"
" %s\n", fmt_string));
return err;
}
status_t _AudioAdapterNode::validateProposedOutputFormat(
const media_format& preferredFormat,
media_format& ioProposedFormat) {
status_t err = _inherited::validateProposedOutputFormat(
preferredFormat, ioProposedFormat);
const media_raw_audio_format& w = media_raw_audio_format::wildcard;
if(input().source != media_source::null) {
if(
ioProposedFormat.u.raw_audio.format != w.format &&
ioProposedFormat.u.raw_audio.channel_count != w.channel_count) {
size_t target_buffer_size =
bytes_per_frame(ioProposedFormat.u.raw_audio) *
frames_per_buffer(input().format.u.raw_audio);
if(ioProposedFormat.u.raw_audio.buffer_size != target_buffer_size) {
if(ioProposedFormat.u.raw_audio.buffer_size != w.buffer_size)
err = B_MEDIA_BAD_FORMAT;
ioProposedFormat.u.raw_audio.buffer_size = target_buffer_size;
}
}
if(ioProposedFormat.u.raw_audio.frame_rate != input().format.u.raw_audio.frame_rate) {
if(ioProposedFormat.u.raw_audio.frame_rate != w.frame_rate)
err = B_MEDIA_BAD_FORMAT;
ioProposedFormat.u.raw_audio.frame_rate = input().format.u.raw_audio.frame_rate;
}
}
char fmt_string[256];
string_for_format(ioProposedFormat, fmt_string, 255);
PRINT((
"### _AudioAdapterNode::validateProposedOutputFormat():\n"
" %s\n", fmt_string));
return err;
}
void
_AudioAdapterNode::SetParameterValue(int32 id, bigtime_t changeTime, const void *value, size_t size)
{
switch(id) {
case _AudioAdapterParams::P_INPUT_FORMAT:
if(input().source != media_source::null) {
media_multi_audio_format f = input().format.u.raw_audio;
if(size != 4)
return;
f.format = *(uint32*)value;
_attemptInputFormatChange(f);
return;
}
break;
case _AudioAdapterParams::P_INPUT_CHANNEL_COUNT:
if(input().source != media_source::null) {
media_multi_audio_format f = input().format.u.raw_audio;
if(size != 4)
return;
f.channel_count = *(uint32*)value;
_attemptInputFormatChange(f);
return;
}
break;
case _AudioAdapterParams::P_OUTPUT_FORMAT:
if(output().source != media_source::null) {
media_multi_audio_format f = output().format.u.raw_audio;
if(size != 4)
return;
f.format = *(uint32*)value;
_attemptOutputFormatChange(f);
return;
}
break;
case _AudioAdapterParams::P_OUTPUT_CHANNEL_COUNT:
if(output().source != media_source::null) {
media_multi_audio_format f = output().format.u.raw_audio;
if(size != 4)
return;
f.channel_count = *(uint32*)value;
_attemptOutputFormatChange(f);
return;
}
break;
}
return _inherited::SetParameterValue(id, changeTime, value, size);
}
status_t _AudioAdapterNode::Connected(
const media_source& source,
const media_destination& destination,
const media_format& format,
media_input* outInput) {
status_t err = _inherited::Connected(
source, destination, format, outInput);
if(err == B_OK) {
_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
ASSERT(p);
p->inputFormat = format.u.raw_audio;
_broadcastInputFormatParams();
}
return err;
}
void _AudioAdapterNode::Connect(
status_t status,
const media_source& source,
const media_destination& destination,
const media_format& format,
char* ioName) {
if(status == B_OK) {
_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
ASSERT(p);
p->outputFormat = format.u.raw_audio;
_broadcastOutputFormatParams();
}
_inherited::Connect(
status, source, destination, format, ioName);
}
void _AudioAdapterNode::_attemptInputFormatChange(
const media_multi_audio_format& format) {
char fmtString[256];
media_format f;
f.type = B_MEDIA_RAW_AUDIO;
f.u.raw_audio = format;
string_for_format(f, fmtString, 256);
PRINT((
"_AudioAdapterNode::attemptInputFormatChange():\n '%s'\n",
fmtString));
_broadcastInputFormatParams();
}
void _AudioAdapterNode::_attemptOutputFormatChange(
const media_multi_audio_format& format) {
char fmtString[256];
media_format f;
f.type = B_MEDIA_RAW_AUDIO;
f.u.raw_audio = format;
string_for_format(f, fmtString, 256);
PRINT((
"_AudioAdapterNode::attemptOutputFormatChange():\n '%s'\n",
fmtString));
media_destination dest = output().destination;
if(dest == media_destination::null) {
PRINT((
"! output not connected!\n"));
return;
}
_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
ASSERT(p);
status_t err;
if(format.format == media_raw_audio_format::wildcard.format ||
format.channel_count == media_raw_audio_format::wildcard.channel_count) {
PRINT((
"! wildcards not allowed\n"));
goto broadcast;
}
err = prepareFormatChange(f);
if(err < B_OK)
{
PRINT((
"! format not supported\n"));
goto broadcast;
}
err = ProposeFormatChange(&f, dest);
if(err < B_OK)
{
PRINT((
"! format rejected\n"));
goto broadcast;
}
err = ChangeFormat(
output().source,
dest,
&f);
if(err < B_OK) {
PRINT(("! ChangeFormat(): %s\n", strerror(err)));
goto broadcast;
}
p->outputFormat = format;
doFormatChange(f);
broadcast:
_broadcastOutputFormatParams();
}
void
_AudioAdapterNode::_broadcastInputFormatParams()
{
PRINT(("_AudioAdapterNode::_broadcastInputFormatParams()\n"));
BroadcastNewParameterValue(
0LL,
_AudioAdapterParams::P_INPUT_FORMAT,
(void*)&input().format.u.raw_audio.format,
4);
BroadcastNewParameterValue(
0LL,
_AudioAdapterParams::P_INPUT_CHANNEL_COUNT,
(void*)&input().format.u.raw_audio.channel_count,
4);
}
void
_AudioAdapterNode::_broadcastOutputFormatParams()
{
PRINT(("_AudioAdapterNode::_broadcastOutputFormatParams()\n"));
BroadcastNewParameterValue(
0LL,
_AudioAdapterParams::P_OUTPUT_FORMAT,
(void*)&output().format.u.raw_audio.format,
4);
BroadcastNewParameterValue(
0LL,
_AudioAdapterParams::P_OUTPUT_CHANNEL_COUNT,
(void*)&output().format.u.raw_audio.channel_count,
4);
}