/* * 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. */ // AudioAdapterNode.cpp #include "AudioAdapterNode.h" #include "AudioAdapterParams.h" #include "SoundUtils.h" #include #include // -------------------------------------------------------- // // ctor/dtor // -------------------------------------------------------- // _AudioAdapterNode::~_AudioAdapterNode() {} _AudioAdapterNode::_AudioAdapterNode( const char* name, IAudioOpFactory* opFactory, BMediaAddOn* addOn) : BMediaNode(name), AudioFilterNode(name, opFactory, addOn) { // PRINT(( // "\n" // "--*-- _AudioAdapterNode() [%s] --*--\n\n", // __BUILD_DATE__)); } // -------------------------------------------------------- // // AudioFilterNode // -------------------------------------------------------- // status_t _AudioAdapterNode::getRequiredInputFormat( media_format& ioFormat) { status_t err = getPreferredInputFormat(ioFormat); if(err < B_OK) return err; // 16sep99: input byte-swapping now supported ioFormat.u.raw_audio.byte_order = media_raw_audio_format::wildcard.byte_order; // 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); // media_raw_audio_format& w = media_raw_audio_format::wildcard; // copy user preferences ioFormat.u.raw_audio.format = p->inputFormat.format; ioFormat.u.raw_audio.channel_count = p->inputFormat.channel_count; // don't require a buffer size until format & channel_count are known [16sep99] ioFormat.u.raw_audio.buffer_size = media_raw_audio_format::wildcard.buffer_size; if(output().destination == media_destination::null) { // frame rate isn't constrained yet ioFormat.u.raw_audio.frame_rate = media_raw_audio_format::wildcard.frame_rate; } return B_OK; } // +++++ 17sep99: use parameter data! 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; media_raw_audio_format& w = media_raw_audio_format::wildcard; // copy user preferences 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 one end is connected, prefer not to do channel conversions [15sep99] // if(output().destination != media_destination::null) // ioFormat.u.raw_audio.channel_count = output().format.u.raw_audio.channel_count; // if output connected, constrain: // buffer_size // frame_rate if(output().destination != media_destination::null) { // if the user doesn't care, default to the output's frame format 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); // media_raw_audio_format& w = media_raw_audio_format::wildcard; // copy user preferences ioFormat.u.raw_audio.format = p->outputFormat.format; ioFormat.u.raw_audio.channel_count = p->outputFormat.channel_count; // don't require a buffer size until format & channel_count are known [16sep99] ioFormat.u.raw_audio.buffer_size = media_raw_audio_format::wildcard.buffer_size; if(input().source == media_source::null) { // frame rate isn't constrained yet ioFormat.u.raw_audio.frame_rate = media_raw_audio_format::wildcard.frame_rate; } return B_OK; } // +++++ 17sep99: use parameter data! 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); media_raw_audio_format& w = media_raw_audio_format::wildcard; // copy user preferences 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 one end is connected, prefer not to do channel conversions [15sep99] //// if(input().source != media_source::null) //// ioFormat.u.raw_audio.channel_count = input().format.u.raw_audio.channel_count; // if input connected, constrain: // buffer_size // frame_rate if(input().source != media_source::null) { // if the user doesn't care, default to the input's frame format 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); media_raw_audio_format& w = media_raw_audio_format::wildcard; if(output().destination != media_destination::null) { // an output connection exists; constrain the input format // is there enough information to suggest a buffer size? 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; } } // require output frame rate 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); media_raw_audio_format& w = media_raw_audio_format::wildcard; if(input().source != media_source::null) { // an input connection exists; constrain the output format // is there enough information to suggest a buffer size? 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; } } // require same frame rate as input 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); } // -------------------------------------------------------- // // BBufferProducer/Consumer // -------------------------------------------------------- // 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)); // +++++ reject attempt: broadcast params for current format _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; // disallow wildcards 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; } // store new format p->outputFormat = format; // inform AudioFilterNode of format change 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); // BroadcastChangedParameter(_AudioAdapterParams::P_INPUT_FORMAT); // BroadcastChangedParameter(_AudioAdapterParams::P_INPUT_CHANNEL_COUNT); } 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); // BroadcastChangedParameter(_AudioAdapterParams::P_OUTPUT_FORMAT); // BroadcastChangedParameter(_AudioAdapterParams::P_OUTPUT_CHANNEL_COUNT); } // END -- AudioAdapterNode.cpp --