/*
* Copyright (C) 2005-2008 by Pieter Palmers
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free Firewire (pro-)audio drivers for linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "avc_plug.h"
#include "avc_unit.h"
#include "avc_signal_format.h"
#include "avc_extended_plug_info.h"
#include "libieee1394/configrom.h"
#include "libieee1394/ieee1394service.h"
#include "libutil/cmd_serialize.h"
#include
namespace AVC {
int Plug::m_globalIdCounter = 0;
IMPL_DEBUG_MODULE( Plug, Plug, DEBUG_LEVEL_NORMAL );
IMPL_DEBUG_MODULE( PlugManager, PlugManager, DEBUG_LEVEL_NORMAL );
Plug::Plug( Unit* unit,
Subunit* subunit,
function_block_type_t functionBlockType,
function_block_id_t functionBlockId,
EPlugAddressType plugAddressType,
EPlugDirection plugDirection,
plug_id_t plugId )
: m_unit( unit )
, m_subunit( subunit )
, m_functionBlockType( functionBlockType )
, m_functionBlockId( functionBlockId )
, m_addressType( plugAddressType )
, m_direction( plugDirection )
, m_id( plugId )
, m_infoPlugType( eAPT_Unknown )
, m_nrOfChannels( 0 )
, m_globalId( m_globalIdCounter++ )
{
debugOutput( DEBUG_LEVEL_VERBOSE,
"nodeId = %d, subunitType = %d, "
"subunitId = %d, functionBlockType = %d, "
"functionBlockId = %d, addressType = %d, "
"direction = %d, id = %d\n",
m_unit->getConfigRom().getNodeId(),
getSubunitType(),
getSubunitId(),
m_functionBlockType,
m_functionBlockId,
m_addressType,
m_direction,
m_id );
}
Plug::Plug( const Plug& rhs )
: m_unit ( rhs.m_unit )
, m_subunit ( rhs.m_subunit )
, m_functionBlockType( rhs.m_functionBlockType )
, m_functionBlockId( rhs.m_functionBlockId )
, m_addressType( rhs.m_addressType )
, m_direction( rhs.m_direction )
, m_id( rhs.m_id )
, m_infoPlugType( rhs.m_infoPlugType )
, m_nrOfChannels( rhs.m_nrOfChannels )
, m_name( rhs.m_name )
, m_clusterInfos( rhs.m_clusterInfos )
, m_formatInfos( rhs.m_formatInfos )
{
if ( getDebugLevel() ) {
setDebugLevel( DEBUG_LEVEL_VERBOSE );
}
}
Plug::Plug()
: m_unit( NULL )
, m_subunit( NULL )
, m_functionBlockType( 0 )
, m_functionBlockId( 0 )
, m_addressType( eAPA_Undefined )
, m_direction( eAPD_Unknown )
, m_id( 0 )
, m_infoPlugType( eAPT_Unknown )
, m_nrOfChannels( 0 )
, m_globalId( 0 )
{
}
Plug::~Plug()
{
m_unit->getPlugManager().remPlug( *this );
}
void
Plug::setVerboseLevel(int l)
{
setDebugLevel(l);
debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Setting verbose level to %d...\n", l );
}
ESubunitType
Plug::getSubunitType() const
{
return (m_subunit==NULL?eST_Unit:m_subunit->getSubunitType());
}
subunit_id_t
Plug::getSubunitId() const
{
return (m_subunit==NULL?0xFF:m_subunit->getSubunitId());
}
bool
Plug::discover()
{
if ( !initFromDescriptor() ) {
debugOutput(DEBUG_LEVEL_NORMAL,
"discover: Could not init plug from descriptor (%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
// return false;
}
if ( !discoverPlugType() ) {
debugOutput(DEBUG_LEVEL_NORMAL,
"discover: Could not discover plug type (%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverName() ) {
debugOutput(DEBUG_LEVEL_NORMAL,
"Could not discover name (%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverNoOfChannels() ) {
debugError( "Could not discover number of channels "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverChannelPosition() ) {
debugOutput(DEBUG_LEVEL_NORMAL,
"Could not discover channel positions "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverChannelName() ) {
debugOutput(DEBUG_LEVEL_NORMAL,
"Could not discover channel name "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverClusterInfo() ) {
debugOutput(DEBUG_LEVEL_NORMAL,
"Could not discover cluster info "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverStreamFormat() ) {
debugOutput(DEBUG_LEVEL_NORMAL,
"Could not discover stream format "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
// return false;
}
if ( !discoverSupportedStreamFormats() ) {
debugOutput(DEBUG_LEVEL_NORMAL,
"Could not discover supported stream formats "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
// return false;
}
return m_unit->getPlugManager().addPlug( *this );
}
bool
Plug::initFromDescriptor()
{
if(getSubunitType()==eST_Unit) {
debugOutput(DEBUG_LEVEL_VERBOSE, "Not loading unit plug from descriptor.\n");
return true;
} else {
return m_subunit->initPlugFromDescriptor(*this);
}
}
bool
Plug::discoverConnections()
{
return discoverConnectionsInput() && discoverConnectionsOutput();
}
bool
Plug::discoverPlugType()
{
return true;
}
bool
Plug::discoverName()
{
// name already set
if (m_name != "") return true;
m_name = plugAddressTypeToString(getPlugAddressType());
m_name += " ";
m_name += plugTypeToString(getPlugType());
m_name += " ";
m_name += plugDirectionToString(getPlugDirection());
return true;
}
bool
Plug::discoverNoOfChannels()
{
return true;
}
bool
Plug::discoverChannelPosition()
{
return true;
}
bool
Plug::discoverChannelName()
{
return true;
}
bool
Plug::discoverClusterInfo()
{
return true;
}
bool
Plug::discoverStreamFormat()
{
ExtendedStreamFormatCmd extStreamFormatCmd =
setPlugAddrToStreamFormatCmd( ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommand );
extStreamFormatCmd.setVerbose( getDebugLevel() );
if ( !extStreamFormatCmd.fire() ) {
debugError( "stream format command failed\n" );
return false;
}
if ( ( extStreamFormatCmd.getStatus() == ExtendedStreamFormatCmd::eS_NoStreamFormat )
|| ( extStreamFormatCmd.getStatus() == ExtendedStreamFormatCmd::eS_NotUsed ) )
{
debugOutput( DEBUG_LEVEL_VERBOSE,
"No stream format information available\n" );
return true;
}
if ( !extStreamFormatCmd.getFormatInformation() ) {
debugOutput(DEBUG_LEVEL_NORMAL, "No stream format information for plug found -> skip\n" );
return true;
}
if ( extStreamFormatCmd.getFormatInformation()->m_root
!= FormatInformation::eFHR_AudioMusic )
{
debugOutput(DEBUG_LEVEL_NORMAL, "Format hierarchy root is not Audio&Music -> skip\n" );
return true;
}
FormatInformation* formatInfo =
extStreamFormatCmd.getFormatInformation();
FormatInformationStreamsCompound* compoundStream
= dynamic_cast< FormatInformationStreamsCompound* > (
formatInfo->m_streams );
if ( compoundStream ) {
m_samplingFrequency =
compoundStream->m_samplingFrequency;
debugOutput( DEBUG_LEVEL_VERBOSE,
"%s plug %d uses "
"sampling frequency %d, nr of stream infos = %d\n",
getName(),
m_id,
m_samplingFrequency,
compoundStream->m_numberOfStreamFormatInfos );
for ( int i = 1;
i <= compoundStream->m_numberOfStreamFormatInfos;
++i )
{
ClusterInfo* clusterInfo =
const_cast( getClusterInfoByIndex( i ) );
if ( !clusterInfo ) {
debugOutput(DEBUG_LEVEL_NORMAL,
"No matching cluster "
"info found for index %d\n", i );
return false;
}
StreamFormatInfo* streamFormatInfo =
compoundStream->m_streamFormatInfos[ i - 1 ];
debugOutput( DEBUG_LEVEL_VERBOSE,
"number of channels = %d, stream format = %d\n",
streamFormatInfo->m_numberOfChannels,
streamFormatInfo->m_streamFormat );
int nrOfChannels = clusterInfo->m_nrOfChannels;
if ( streamFormatInfo->m_streamFormat ==
FormatInformation::eFHL2_AM824_MIDI_CONFORMANT )
{
// 8 logical midi channels fit into 1 channel
nrOfChannels = ( ( nrOfChannels + 7 ) / 8 );
}
// sanity check
if ( nrOfChannels != streamFormatInfo->m_numberOfChannels )
{
debugOutput(DEBUG_LEVEL_NORMAL,
"Number of channels "
"mismatch: '%s' plug discovering reported "
"%d channels for cluster '%s', while stream "
"format reported %d\n",
getName(),
nrOfChannels,
clusterInfo->m_name.c_str(),
streamFormatInfo->m_numberOfChannels);
}
clusterInfo->m_streamFormat = streamFormatInfo->m_streamFormat;
debugOutput( DEBUG_LEVEL_VERBOSE,
"%s plug %d cluster info %d ('%s'): "
"stream format %d\n",
getName(),
m_id,
i,
clusterInfo->m_name.c_str(),
clusterInfo->m_streamFormat );
}
}
FormatInformationStreamsSync* syncStream
= dynamic_cast< FormatInformationStreamsSync* > (
formatInfo->m_streams );
if ( syncStream ) {
m_samplingFrequency =
syncStream->m_samplingFrequency;
debugOutput( DEBUG_LEVEL_VERBOSE,
"%s plug %d is sync stream with sampling frequency %d\n",
getName(),
m_id,
m_samplingFrequency );
}
if ( !compoundStream && !syncStream )
{
debugError( "Unsupported stream format\n" );
return false;
}
return true;
}
bool
Plug::discoverSupportedStreamFormats()
{
ExtendedStreamFormatCmd extStreamFormatCmd =
setPlugAddrToStreamFormatCmd(
ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommandList);
extStreamFormatCmd.setVerbose( getDebugLevel() );
int i = 0;
bool cmdSuccess = false;
do {
extStreamFormatCmd.setIndexInStreamFormat( i );
extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
cmdSuccess = extStreamFormatCmd.fire();
if ( cmdSuccess
&& ( extStreamFormatCmd.getResponse()
== AVCCommand::eR_Implemented ) )
{
FormatInfo formatInfo;
formatInfo.m_index = i;
bool formatInfoIsValid = true;
FormatInformationStreamsSync* syncStream
= dynamic_cast< FormatInformationStreamsSync* >
( extStreamFormatCmd.getFormatInformation()->m_streams );
if ( syncStream ) {
formatInfo.m_samplingFrequency =
syncStream->m_samplingFrequency;
formatInfo.m_isSyncStream = true ;
}
FormatInformationStreamsCompound* compoundStream
= dynamic_cast< FormatInformationStreamsCompound* >
( extStreamFormatCmd.getFormatInformation()->m_streams );
if ( compoundStream ) {
formatInfo.m_samplingFrequency =
compoundStream->m_samplingFrequency;
formatInfo.m_isSyncStream = false;
for ( int j = 0;
j < compoundStream->m_numberOfStreamFormatInfos;
++j )
{
switch ( compoundStream->m_streamFormatInfos[j]->m_streamFormat ) {
case AVC1394_STREAM_FORMAT_AM824_IEC60968_3:
formatInfo.m_audioChannels +=
compoundStream->m_streamFormatInfos[j]->m_numberOfChannels;
break;
case AVC1394_STREAM_FORMAT_AM824_MULTI_BIT_LINEAR_AUDIO_RAW:
formatInfo.m_audioChannels +=
compoundStream->m_streamFormatInfos[j]->m_numberOfChannels;
break;
case AVC1394_STREAM_FORMAT_AM824_MIDI_CONFORMANT:
formatInfo.m_midiChannels +=
compoundStream->m_streamFormatInfos[j]->m_numberOfChannels;
break;
default:
formatInfoIsValid = false;
debugWarning("unknown stream format (0x%02x) for channel "
"(%d)\n",
compoundStream->m_streamFormatInfos[j]->m_streamFormat,
j );
}
}
}
if ( formatInfoIsValid ) {
flushDebugOutput();
debugOutput( DEBUG_LEVEL_VERBOSE,
"[%s:%d] formatInfo[%d].m_samplingFrequency "
"= %d\n",
getName(), m_id,
i, formatInfo.m_samplingFrequency );
debugOutput( DEBUG_LEVEL_VERBOSE,
"[%s:%d] formatInfo[%d].m_isSyncStream = %d\n",
getName(), m_id,
i, formatInfo.m_isSyncStream );
debugOutput( DEBUG_LEVEL_VERBOSE,
"[%s:%d] formatInfo[%d].m_audioChannels = %d\n",
getName(), m_id,
i, formatInfo.m_audioChannels );
debugOutput( DEBUG_LEVEL_VERBOSE,
"[%s:%d] formatInfo[%d].m_midiChannels = %d\n",
getName(), m_id,
i, formatInfo.m_midiChannels );
m_formatInfos.push_back( formatInfo );
flushDebugOutput();
}
}
++i;
} while ( cmdSuccess && ( extStreamFormatCmd.getResponse()
== ExtendedStreamFormatCmd::eR_Implemented ) );
return true;
}
bool
Plug::discoverConnectionsInput()
{
debugOutput( DEBUG_LEVEL_VERBOSE, "Discovering incoming connections...\n");
int sourcePlugGlobalId=getSignalSource();
if(sourcePlugGlobalId >= 0) {
Plug *p=m_unit->getPlugManager().getPlug(sourcePlugGlobalId);
if (p==NULL) {
debugError( "Plug with global id %d not found\n",sourcePlugGlobalId );
return false;
}
// connected to another plug
debugOutput( DEBUG_LEVEL_VERBOSE, "Plug '%s' gets signal from '%s'...\n",
getName(), p->getName() );
if ( p ) {
debugOutput( DEBUG_LEVEL_VERBOSE,
"'(%d) %s' has a connection to '(%d) %s'\n",
getGlobalId(),
getName(),
p->getGlobalId(),
p->getName() );
addPlugConnection( m_inputConnections, *p );
} else {
debugError( "no corresponding plug found for '(%d) %s'\n",
getGlobalId(),
getName() );
return false;
}
}
return true;
}
bool
Plug::discoverConnectionsOutput()
{
return true;
}
bool
Plug::inquireConnnection( Plug& plug )
{
SignalSourceCmd signalSourceCmd = setSrcPlugAddrToSignalCmd();
setDestPlugAddrToSignalCmd( signalSourceCmd, plug );
signalSourceCmd.setCommandType( AVCCommand::eCT_SpecificInquiry );
signalSourceCmd.setVerbose( getDebugLevel() );
if ( !signalSourceCmd.fire() ) {
debugError( "Could not inquire connection between '%s' and '%s'\n",
getName(), plug.getName() );
return false;
}
if ( signalSourceCmd.getResponse() == AVCCommand::eR_Implemented ) {
debugOutput( DEBUG_LEVEL_VERBOSE,
"Connection possible between '%s' and '%s'\n",
getName(), plug.getName() );
return true;
}
debugOutput( DEBUG_LEVEL_VERBOSE,
"Connection not possible between '%s' and '%s'\n",
getName(), plug.getName() );
return false;
}
int
Plug::getSignalSource()
{
if((getPlugAddressType() == eAPA_PCR) ||
(getPlugAddressType() == eAPA_ExternalPlug)) {
if (getPlugDirection() != eAPD_Output) {
debugOutput(DEBUG_LEVEL_NORMAL, "Signal Source command not valid for non-output unit plugs...\n");
return -1;
}
}
if(getPlugAddressType() == eAPA_SubunitPlug) {
if (getPlugDirection() != eAPD_Input) {
debugOutput(DEBUG_LEVEL_NORMAL, "Signal Source command not valid for non-input subunit plugs...\n");
return -1;
}
}
SignalSourceCmd signalSourceCmd( m_unit->get1394Service() );
signalSourceCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
signalSourceCmd.setSubunitType( eST_Unit );
signalSourceCmd.setSubunitId( 0xff );
SignalSubunitAddress signalSubunitAddr;
signalSubunitAddr.m_subunitType = 0xFF;
signalSubunitAddr.m_subunitId = 0xFF;
signalSubunitAddr.m_plugId = 0xFE;
signalSourceCmd.setSignalSource( signalSubunitAddr );
setDestPlugAddrToSignalCmd( signalSourceCmd, *this );
signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
signalSourceCmd.setVerbose( getDebugLevel() );
if ( !signalSourceCmd.fire() ) {
debugError( "Could not get signal source for '%s'\n",
getName() );
return -1;
}
if ( signalSourceCmd.getResponse() == AVCCommand::eR_Implemented ) {
SignalAddress* src=signalSourceCmd.getSignalSource();
Plug* p=NULL;
if(dynamic_cast(src)) {
SignalUnitAddress *usrc=dynamic_cast(src);
if (usrc->m_plugId & 0x80) {
p=m_unit->getPlugManager().getPlug( eST_Unit, 0xFF,
0xFF, 0xFF, eAPA_ExternalPlug, eAPD_Input,
usrc->m_plugId & 0x7F );
} else {
p=m_unit->getPlugManager().getPlug( eST_Unit, 0xFF,
0xFF, 0xFF, eAPA_PCR, eAPD_Input,
usrc->m_plugId & 0x7F );
}
} else if (dynamic_cast(src)) {
SignalSubunitAddress *susrc=dynamic_cast(src);
p=m_unit->getPlugManager().getPlug( byteToSubunitType(susrc->m_subunitType),
susrc->m_subunitId, 0xFF, 0xFF, eAPA_SubunitPlug,
eAPD_Output, susrc->m_plugId);
} else return -1;
if (p==NULL) {
debugError("reported signal source plug not found\n");
return -1;
}
return p->getGlobalId();
}
return -1;
}
bool
Plug::setConnection( Plug& plug )
{
SignalSourceCmd signalSourceCmd = setSrcPlugAddrToSignalCmd();
setDestPlugAddrToSignalCmd( signalSourceCmd, plug );
signalSourceCmd.setCommandType( AVCCommand::eCT_Control );
signalSourceCmd.setVerbose( getDebugLevel() );
if ( !signalSourceCmd.fire() ) {
debugError( "Could not set connection between '%s' and '%s'\n",
getName(), plug.getName() );
return false;
}
if ( signalSourceCmd.getResponse() == AVCCommand::eR_Accepted ) {
debugOutput( DEBUG_LEVEL_VERBOSE,
"Could set connection between '%s' and '%s'\n",
getName(), plug.getName() );
return true;
}
debugOutput( DEBUG_LEVEL_VERBOSE,
"Could not set connection between '%s' and '%s'\n",
getName(), plug.getName() );
return false;
}
bool
Plug::propagateFromConnectedPlug( ) {
if (getDirection() == eAPD_Output) {
if (getInputConnections().size()==0) {
debugOutput(DEBUG_LEVEL_NORMAL, "No input connections to propagate from, skipping.\n");
return true;
}
if (getInputConnections().size()>1) {
debugOutput(DEBUG_LEVEL_NORMAL, "Too many input connections to propagate from, using first one.\n");
}
Plug* p = *(getInputConnections().begin());
return propagateFromPlug( p );
} else if (getDirection() == eAPD_Input) {
if (getOutputConnections().size()==0) {
debugOutput(DEBUG_LEVEL_NORMAL, "No output connections to propagate from, skipping.\n");
return true;
}
if (getOutputConnections().size()>1) {
debugOutput(DEBUG_LEVEL_NORMAL, "Too many output connections to propagate from, using first one.\n");
}
Plug* p = *(getOutputConnections().begin());
return propagateFromPlug( p );
} else {
debugError("plug with undefined direction\n");
return false;
}
}
bool
Plug::propagateFromPlug( Plug *p ) {
debugOutput( DEBUG_LEVEL_VERBOSE,
"Propagating info from plug '%s' to plug '%s'\n",
p->getName(), getName() );
if (m_clusterInfos.size()==0) {
m_clusterInfos=p->m_clusterInfos;
}
m_nrOfChannels=p->m_nrOfChannels;
return true;
}
int
Plug::getNrOfStreams() const
{
int nrOfChannels = 0;
for ( ClusterInfoVector::const_iterator it = m_clusterInfos.begin();
it != m_clusterInfos.end();
++it )
{
const ClusterInfo* clusterInfo = &( *it );
nrOfChannels += clusterInfo->m_nrOfChannels;
}
return nrOfChannels;
}
int
Plug::getNrOfChannels() const
{
return m_nrOfChannels;
}
bool
Plug::setNrOfChannels(int i)
{
m_nrOfChannels=i;
return true;
}
int
Plug::getSampleRate() const
{
if(getPlugAddressType()==eAPA_PCR) {
if(getPlugDirection()==eAPD_Input) {
InputPlugSignalFormatCmd cmd( m_unit->get1394Service() );
cmd.m_form=0xFF;
cmd.m_eoh=0xFF;
cmd.m_fmt=0xFF;
cmd.m_plug=getPlugId();
cmd.setNodeId( m_unit->getConfigRom().getNodeId() );
cmd.setSubunitType( eST_Unit );
cmd.setSubunitId( 0xff );
cmd.setCommandType( AVCCommand::eCT_Status );
if ( !cmd.fire() ) {
debugError( "input plug signal format command failed\n" );
return 0;
}
if (cmd.m_fmt != 0x10 ) {
debugWarning("Incorrect FMT response received: 0x%02X\n",cmd.m_fmt);
}
return fdfSfcToSampleRate(cmd.m_fdf[0]);
} else if (getPlugDirection()==eAPD_Output) {
OutputPlugSignalFormatCmd cmd( m_unit->get1394Service() );
cmd.m_form=0xFF;
cmd.m_eoh=0xFF;
cmd.m_fmt=0xFF;
cmd.m_plug=getPlugId();
cmd.setNodeId( m_unit->getConfigRom().getNodeId() );
cmd.setSubunitType( eST_Unit );
cmd.setSubunitId( 0xff );
cmd.setCommandType( AVCCommand::eCT_Status );
if ( !cmd.fire() ) {
debugError( "output plug signal format command failed\n" );
return 0;
}
if (cmd.m_fmt != 0x10 ) {
debugWarning("Incorrect FMT response received: 0x%02X\n",cmd.m_fmt);
}
return fdfSfcToSampleRate(cmd.m_fdf[0]);
} else {
debugError("PCR plug with undefined direction.\n");
return 0;
}
}
// fallback
return convertESamplingFrequency( static_cast( m_samplingFrequency ) );
}
bool
Plug::setSampleRate( int rate )
{
// apple style
if(getPlugAddressType()==eAPA_PCR) {
if(getPlugDirection()==eAPD_Input) {
InputPlugSignalFormatCmd cmd( m_unit->get1394Service() );
cmd.m_eoh=1;
cmd.m_form=0;
cmd.m_fmt=0x10;
cmd.m_plug=getPlugId();
cmd.m_fdf[0]=sampleRateToFdfSfc(rate);
cmd.m_fdf[1]=0xFF;
cmd.m_fdf[2]=0xFF;
cmd.setNodeId( m_unit->getConfigRom().getNodeId() );
cmd.setSubunitType( eST_Unit );
cmd.setSubunitId( 0xff );
cmd.setCommandType( AVCCommand::eCT_Control );
if ( !cmd.fire() ) {
debugError( "input plug signal format command failed\n" );
return false;
}
if ( cmd.getResponse() == AVCCommand::eR_Accepted )
{
return true;
}
debugWarning( "output plug signal format command not accepted\n" );
} else if (getPlugDirection()==eAPD_Output) {
OutputPlugSignalFormatCmd cmd( m_unit->get1394Service() );
cmd.m_eoh=1;
cmd.m_form=0;
cmd.m_fmt=0x10;
cmd.m_plug=getPlugId();
cmd.m_fdf[0]=sampleRateToFdfSfc(rate);
cmd.m_fdf[1]=0xFF;
cmd.m_fdf[2]=0xFF;
cmd.setNodeId( m_unit->getConfigRom().getNodeId() );
cmd.setSubunitType( eST_Unit );
cmd.setSubunitId( 0xff );
cmd.setCommandType( AVCCommand::eCT_Control );
if ( !cmd.fire() ) {
debugError( "output plug signal format command failed\n" );
return false;
}
if ( cmd.getResponse() == AVCCommand::eR_Accepted )
{
return true;
}
debugWarning( "output plug signal format command not accepted\n" );
} else {
debugError("PCR plug with undefined direction.\n");
return false;
}
}
// fallback: BeBoB style
ESamplingFrequency samplingFrequency = parseSampleRate(rate);
ExtendedStreamFormatCmd extStreamFormatCmd(
m_unit->get1394Service(),
ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommandList );
UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
getPlugId() );
extStreamFormatCmd.setPlugAddress(
PlugAddress(
Plug::convertPlugDirection(getPlugDirection() ),
PlugAddress::ePAM_Unit,
unitPlugAddress ) );
extStreamFormatCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
int i = 0;
bool cmdSuccess = false;
bool correctFormatFound = false;
do {
extStreamFormatCmd.setIndexInStreamFormat( i );
extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
extStreamFormatCmd.setVerbose( getDebugLevel() );
cmdSuccess = extStreamFormatCmd.fire();
if ( cmdSuccess
&& ( extStreamFormatCmd.getResponse() ==
AVCCommand::eR_Implemented ) )
{
ESamplingFrequency foundFreq = eSF_DontCare;
FormatInformation* formatInfo =
extStreamFormatCmd.getFormatInformation();
FormatInformationStreamsCompound* compoundStream
= dynamic_cast< FormatInformationStreamsCompound* > (
formatInfo->m_streams );
if ( compoundStream ) {
foundFreq =
static_cast< ESamplingFrequency >(
compoundStream->m_samplingFrequency );
}
FormatInformationStreamsSync* syncStream
= dynamic_cast< FormatInformationStreamsSync* > (
formatInfo->m_streams );
if ( syncStream ) {
foundFreq =
static_cast< ESamplingFrequency >(
syncStream->m_samplingFrequency );
}
if ( foundFreq == samplingFrequency )
{
correctFormatFound = true;
break;
}
}
++i;
} while ( cmdSuccess
&& ( extStreamFormatCmd.getResponse() ==
ExtendedStreamFormatCmd::eR_Implemented ) );
if ( !cmdSuccess ) {
debugError( "setSampleRatePlug: Failed to retrieve format info\n" );
return false;
}
if ( !correctFormatFound ) {
debugError( "setSampleRatePlug: %s plug %d does not support "
"sample rate %d\n",
getName(),
getPlugId(),
convertESamplingFrequency( samplingFrequency ) );
return false;
}
extStreamFormatCmd.setSubFunction(
ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommand );
extStreamFormatCmd.setCommandType( AVCCommand::eCT_Control );
extStreamFormatCmd.setVerbose( getDebugLevel() );
if ( !extStreamFormatCmd.fire() ) {
debugError( "setSampleRate: Could not set sample rate %d "
"to %s plug %d\n",
convertESamplingFrequency( samplingFrequency ),
getName(),
getPlugId() );
return false;
}
return true;
}
bool
Plug::discoverConnectionsFromSpecificData(
EPlugDirection discoverDirection,
PlugAddressSpecificData* plugAddress,
PlugVector& connections )
{
UnitPlugSpecificDataPlugAddress* pUnitPlugAddress =
dynamic_cast
( plugAddress->m_plugAddressData );
SubunitPlugSpecificDataPlugAddress* pSubunitPlugAddress =
dynamic_cast
( plugAddress->m_plugAddressData );
FunctionBlockPlugSpecificDataPlugAddress*
pFunctionBlockPlugAddress =
dynamic_cast
( plugAddress->m_plugAddressData );
Plug* plug = getPlugDefinedBySpecificData(
pUnitPlugAddress,
pSubunitPlugAddress,
pFunctionBlockPlugAddress );
if ( plug ) {
debugOutput( DEBUG_LEVEL_VERBOSE,
"'(%d) %s' has a connection to '(%d) %s'\n",
getGlobalId(),
getName(),
plug->getGlobalId(),
plug->getName() );
addPlugConnection( connections, *plug );
} else {
debugError( "no corresponding plug found for '(%d) %s'\n",
getGlobalId(),
getName() );
return false;
}
return true;
}
bool
Plug::addPlugConnection( PlugVector& connections,
Plug& plug )
{
for ( PlugVector::iterator it = connections.begin();
it != connections.end();
++it )
{
Plug* cPlug = *it;
if ( cPlug == &plug ) {
debugOutput( DEBUG_LEVEL_VERBOSE,
"plug '%s' already in connection list\n",
plug.getName() );
return true;
}
}
connections.push_back( &plug );
return true;
}
SignalSourceCmd
Plug::setSrcPlugAddrToSignalCmd()
{
SignalSourceCmd signalSourceCmd( m_unit->get1394Service() );
switch( getSubunitType() ) {
case eST_Unit:
{
SignalUnitAddress signalUnitAddr;
if ( getPlugAddressType() == eAPA_ExternalPlug ) {
signalUnitAddr.m_plugId = m_id + 0x80;
} else {
signalUnitAddr.m_plugId = m_id;
}
signalSourceCmd.setSignalSource( signalUnitAddr );
}
break;
case eST_Music:
case eST_Audio:
{
SignalSubunitAddress signalSubunitAddr;
signalSubunitAddr.m_subunitType = getSubunitType();
signalSubunitAddr.m_subunitId = getSubunitId();
signalSubunitAddr.m_plugId = m_id;
signalSourceCmd.setSignalSource( signalSubunitAddr );
}
break;
default:
debugError( "Unknown subunit type\n" );
}
signalSourceCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
signalSourceCmd.setSubunitType( eST_Unit );
signalSourceCmd.setSubunitId( 0xff );
return signalSourceCmd;
}
void
Plug::setDestPlugAddrToSignalCmd(SignalSourceCmd& signalSourceCmd,
Plug& plug)
{
switch( plug.getSubunitType() ) {
case eST_Unit:
{
SignalUnitAddress signalUnitAddr;
if ( plug.getPlugAddressType() == eAPA_ExternalPlug ) {
signalUnitAddr.m_plugId = plug.m_id + 0x80;
} else {
signalUnitAddr.m_plugId = plug.m_id;
}
signalSourceCmd.setSignalDestination( signalUnitAddr );
}
break;
case eST_Music:
case eST_Audio:
{
SignalSubunitAddress signalSubunitAddr;
signalSubunitAddr.m_subunitType = plug.getSubunitType();
signalSubunitAddr.m_subunitId = plug.getSubunitId();
signalSubunitAddr.m_plugId = plug.m_id;
signalSourceCmd.setSignalDestination( signalSubunitAddr );
}
break;
default:
debugError( "Unknown subunit type\n" );
}
}
void
Plug::debugOutputClusterInfos( int debugLevel )
{
for ( ClusterInfoVector::const_iterator it = m_clusterInfos.begin();
it != m_clusterInfos.end();
++it )
{
const ClusterInfo* clusterInfo = &( *it );
debugOutput( debugLevel, "number of channels: %d\n",
clusterInfo->m_nrOfChannels );
for ( ChannelInfoVector::const_iterator cit
= clusterInfo->m_channelInfos.begin();
cit != clusterInfo->m_channelInfos.end();
++cit )
{
const ChannelInfo* channelInfo = &( *cit );
channelInfo = channelInfo;
debugOutput( debugLevel,
"stream position: %d\n",
channelInfo->m_streamPosition );
debugOutput( debugLevel,
"location: %d\n",
channelInfo->m_location );
}
}
}
const Plug::ClusterInfo*
Plug::getClusterInfoByIndex(int index) const
{
for ( Plug::ClusterInfoVector::const_iterator clit =
m_clusterInfos.begin();
clit != m_clusterInfos.end();
++clit )
{
const ClusterInfo* info = &*clit;
if ( info->m_index == index ) {
return info;
}
}
return 0;
}
PlugAddress::EPlugDirection
Plug::convertPlugDirection( EPlugDirection direction )
{
PlugAddress::EPlugDirection dir;
switch ( direction ) {
case Plug::eAPD_Input:
dir = PlugAddress::ePD_Input;
break;
case Plug::eAPD_Output:
dir = PlugAddress::ePD_Output;
break;
default:
dir = PlugAddress::ePD_Undefined;
}
return dir;
}
std::string
Plug::plugAddressTypeToString(enum EPlugAddressType t) {
switch (t) {
case eAPA_PCR:
return string("PCR");
case eAPA_ExternalPlug:
return string("External");
case eAPA_AsynchronousPlug:
return string("Async");
case eAPA_SubunitPlug:
return string("Subunit");
case eAPA_FunctionBlockPlug:
return string("Function Block");
default:
case eAPA_Undefined:
return string("Undefined");
}
}
std::string
Plug::plugTypeToString(enum EPlugType t) {
switch (t) {
case eAPT_IsoStream:
return string("IsoStream");
case eAPT_AsyncStream:
return string("AsyncStream");
case eAPT_Midi:
return string("MIDI");
case eAPT_Sync:
return string("Sync");
case eAPT_Analog:
return string("Analog");
case eAPT_Digital:
return string("Digital");
default:
case eAPT_Unknown:
return string("Unknown");
}
}
std::string
Plug::plugDirectionToString(enum EPlugDirection t) {
switch (t) {
case eAPD_Input:
return string("Input");
case eAPD_Output:
return string("Output");
default:
case eAPT_Unknown:
return string("Unknown");
}
}
void
Plug::showPlug() const
{
#ifdef DEBUG
debugOutput( DEBUG_LEVEL_VERBOSE, "\tName = %s\n",
getName() );
debugOutput( DEBUG_LEVEL_VERBOSE, "\tType = %s\n",
extendedPlugInfoPlugTypeToString( getPlugType() ) );
debugOutput( DEBUG_LEVEL_VERBOSE, "\tAddress Type = %s\n",
avPlugAddressTypeToString( getPlugAddressType() ) );
debugOutput( DEBUG_LEVEL_VERBOSE, "\tId = %d\n",
getPlugId() );
debugOutput( DEBUG_LEVEL_VERBOSE, "\tSubunitType = %d\n",
getSubunitType() );
debugOutput( DEBUG_LEVEL_VERBOSE, "\tSubunitId = %d\n",
getSubunitId() );
debugOutput( DEBUG_LEVEL_VERBOSE, "\tDirection = %s\n",
avPlugDirectionToString( getPlugDirection() ) );
debugOutput( DEBUG_LEVEL_VERBOSE, "\tSampling Rate = %d\n",
getSampleRate() );
debugOutput( DEBUG_LEVEL_VERBOSE, "\tNumber of Channels = %d\n",
getNrOfChannels() );
debugOutput( DEBUG_LEVEL_VERBOSE, "\tNumber of Streams = %d\n",
getNrOfStreams() );
debugOutput( DEBUG_LEVEL_VERBOSE, "\tIncoming connections from: ");
for ( PlugVector::const_iterator it = m_inputConnections.begin();
it != m_inputConnections.end();
++it )
{
debugOutputShort(DEBUG_LEVEL_VERBOSE, "%s, ", (*it)->getName());
}
debugOutputShort(DEBUG_LEVEL_VERBOSE, "\n");
debugOutput( DEBUG_LEVEL_VERBOSE, "\tOutgoing connections to: ");
for ( PlugVector::const_iterator it = m_outputConnections.begin();
it != m_outputConnections.end();
++it )
{
debugOutputShort(DEBUG_LEVEL_VERBOSE, "%s, ", (*it)->getName());
}
debugOutputShort(DEBUG_LEVEL_VERBOSE, "\n");
debugOutput( DEBUG_LEVEL_VERBOSE, "\tChannel info:\n");
unsigned int i=0;
for ( Plug::ClusterInfoVector::const_iterator it = m_clusterInfos.begin();
it != m_clusterInfos.end();
++it )
{
const Plug::ClusterInfo* clusterInfo = &( *it );
debugOutput(DEBUG_LEVEL_VERBOSE, " Cluster %s (idx=%2d, type=0x%02X, ch=%2d, format=0x%02X)\n",
clusterInfo->m_name.c_str(), i, clusterInfo->m_portType, clusterInfo->m_nrOfChannels, clusterInfo->m_streamFormat);
Plug::ChannelInfoVector channelInfos = clusterInfo->m_channelInfos;
for ( Plug::ChannelInfoVector::const_iterator it = channelInfos.begin();
it != channelInfos.end();
++it )
{
const Plug::ChannelInfo* channelInfo = &( *it );
debugOutput(DEBUG_LEVEL_VERBOSE, " Channel %s (pos=0x%02X, loc=0x%02X)\n",
channelInfo->m_name.c_str(), channelInfo->m_streamPosition, channelInfo->m_location);
}
i++;
}
flushDebugOutput();
#endif
}
Plug*
Plug::getPlugDefinedBySpecificData(
UnitPlugSpecificDataPlugAddress* pUnitPlugAddress,
SubunitPlugSpecificDataPlugAddress* pSubunitPlugAddress,
FunctionBlockPlugSpecificDataPlugAddress* pFunctionBlockPlugAddress )
{
subunit_type_t subunitType = 0xff;
subunit_id_t subunitId = 0xff;
function_block_type_t functionBlockType = 0xff;
function_block_id_t functionBlockId = 0xff;
EPlugAddressType addressType = eAPA_Undefined;
EPlugDirection direction = eAPD_Unknown;
plug_id_t plugId = 0xff;
if ( !pUnitPlugAddress
&& !pSubunitPlugAddress
&& !pFunctionBlockPlugAddress )
{
debugError( "No correct specific data found\n" );
return 0;
}
if ( pUnitPlugAddress ) {
subunitType = eST_Unit;
switch ( pUnitPlugAddress->m_plugType ) {
case UnitPlugSpecificDataPlugAddress::ePT_PCR:
addressType = eAPA_PCR;
break;
case UnitPlugSpecificDataPlugAddress::ePT_ExternalPlug:
addressType = eAPA_ExternalPlug;
break;
case UnitPlugSpecificDataPlugAddress::ePT_AsynchronousPlug:
addressType = eAPA_AsynchronousPlug;
break;
}
// unit plug have only connections to subunits
if ( getPlugAddressType() == eAPA_SubunitPlug ) {
direction = getDirection();
} else {
debugError( "Function block has connection from/to unknown "
"plug type\n" );
direction = eAPD_Unknown;
}
plugId = pUnitPlugAddress->m_plugId;
debugOutput( DEBUG_LEVEL_VERBOSE,
"'(%d) %s': Remote plug is a unit plug "
"(%s, %s, %d)\n",
getGlobalId(),
getName(),
avPlugAddressTypeToString( addressType ),
avPlugDirectionToString( direction ),
plugId );
}
if ( pSubunitPlugAddress ) {
subunitType = pSubunitPlugAddress->m_subunitType;
subunitId = pSubunitPlugAddress->m_subunitId;
addressType = eAPA_SubunitPlug;
if ( getPlugAddressType() == eAPA_FunctionBlockPlug ) {
direction = getDirection();
} else if ( getPlugAddressType() == eAPA_SubunitPlug ) {
direction = toggleDirection( getDirection() );
} else {
// unit
direction = getDirection();
}
plugId = pSubunitPlugAddress->m_plugId;
debugOutput( DEBUG_LEVEL_VERBOSE,
"'(%d) %s': Remote plug is a subunit plug "
"(%d, %d, %s, %d)\n",
getGlobalId(),
getName(),
subunitType,
subunitId,
avPlugDirectionToString( direction ),
plugId );
}
if ( pFunctionBlockPlugAddress ) {
subunitType = pFunctionBlockPlugAddress->m_subunitType;
subunitId = pFunctionBlockPlugAddress->m_subunitId;
functionBlockType = pFunctionBlockPlugAddress->m_functionBlockType;
functionBlockId = pFunctionBlockPlugAddress->m_functionBlockId;
addressType = eAPA_FunctionBlockPlug;
if ( getPlugAddressType() == eAPA_FunctionBlockPlug ) {
direction = toggleDirection( getDirection() );
} else if ( getPlugAddressType() == eAPA_SubunitPlug ){
direction = getDirection();
} else {
debugError( "Function block has connection from/to unknown "
"plug type\n" );
direction = eAPD_Unknown;
}
plugId = pFunctionBlockPlugAddress->m_plugId;
debugOutput( DEBUG_LEVEL_VERBOSE,
"'(%d) %s': Remote plug is a functionblock plug "
"(%d, %d, %d, %d, %s, %d)\n",
getGlobalId(),
getName(),
subunitType,
subunitId,
functionBlockType,
functionBlockId,
avPlugDirectionToString( direction ),
plugId );
}
ESubunitType enumSubunitType =
static_cast( subunitType );
return m_unit->getPlugManager().getPlug(
enumSubunitType,
subunitId,
functionBlockType,
functionBlockId,
addressType,
direction,
plugId );
}
Plug::EPlugDirection
Plug::toggleDirection( EPlugDirection direction ) const
{
EPlugDirection newDirection;
switch ( direction ) {
case eAPD_Output:
newDirection = eAPD_Input;
break;
case eAPD_Input:
newDirection = eAPD_Output;
break;
default:
newDirection = direction;
}
return newDirection;
}
bool
Plug::serializeChannelInfos( Glib::ustring basePath,
Util::IOSerialize& ser,
const ClusterInfo& clusterInfo ) const
{
bool result = true;
int i = 0;
for ( ChannelInfoVector::const_iterator it = clusterInfo.m_channelInfos.begin();
it != clusterInfo.m_channelInfos.end();
++it )
{
const ChannelInfo& info = *it;
std::ostringstream strstrm;
strstrm << basePath << i;
result &= ser.write( strstrm.str() + "/m_streamPosition", info.m_streamPosition );
result &= ser.write( strstrm.str() + "/m_location", info.m_location );
result &= ser.write( strstrm.str() + "/m_name", info.m_name );
i++;
}
return result;
}
bool
Plug::deserializeChannelInfos( Glib::ustring basePath,
Util::IODeserialize& deser,
ClusterInfo& clusterInfo )
{
int i = 0;
bool bFinished = false;
bool result = true;
do {
std::ostringstream strstrm;
strstrm << basePath << i;
// check for one element to exist. when one exist the other elements
// must also be there. otherwise just return (last) result.
if ( deser.isExisting( strstrm.str() + "/m_streamPosition" ) ) {
ChannelInfo info;
result &= deser.read( strstrm.str() + "/m_streamPosition", info.m_streamPosition );
result &= deser.read( strstrm.str() + "/m_location", info.m_location );
result &= deser.read( strstrm.str() + "/m_name", info.m_name );
if ( result ) {
clusterInfo.m_channelInfos.push_back( info );
i++;
} else {
bFinished = true;
}
} else {
bFinished = true;
}
} while ( !bFinished );
return result;
}
bool
Plug::serializeClusterInfos( Glib::ustring basePath,
Util::IOSerialize& ser ) const
{
bool result = true;
int i = 0;
for ( ClusterInfoVector::const_iterator it = m_clusterInfos.begin();
it != m_clusterInfos.end();
++it )
{
const ClusterInfo& info = *it;
std::ostringstream strstrm;
strstrm << basePath << i;
result &= ser.write( strstrm.str() + "/m_index", info.m_index );
result &= ser.write( strstrm.str() + "/m_portType", info.m_portType );
result &= ser.write( strstrm.str() + "/m_name", info.m_name );
result &= ser.write( strstrm.str() + "/m_nrOfChannels", info.m_nrOfChannels );
result &= serializeChannelInfos( strstrm.str() + "/m_channelInfo", ser, info );
result &= ser.write( strstrm.str() + "/m_streamFormat", info.m_streamFormat );
i++;
}
return result;
}
bool
Plug::deserializeClusterInfos( Glib::ustring basePath,
Util::IODeserialize& deser )
{
int i = 0;
bool bFinished = false;
bool result = true;
do {
std::ostringstream strstrm;
strstrm << basePath << i;
// check for one element to exist. when one exist the other elements
// must also be there. otherwise just return (last) result.
if ( deser.isExisting( strstrm.str() + "/m_index" ) ) {
ClusterInfo info;
result &= deser.read( strstrm.str() + "/m_index", info.m_index );
result &= deser.read( strstrm.str() + "/m_portType", info.m_portType );
result &= deser.read( strstrm.str() + "/m_name", info.m_name );
result &= deser.read( strstrm.str() + "/m_nrOfChannels", info.m_nrOfChannels );
result &= deserializeChannelInfos( strstrm.str() + "/m_channelInfo", deser, info );
result &= deser.read( strstrm.str() + "/m_streamFormat", info.m_streamFormat );
if ( result ) {
m_clusterInfos.push_back( info );
i++;
} else {
bFinished = true;
}
} else {
bFinished = true;
}
} while ( !bFinished );
return result;
}
bool
Plug::serializeFormatInfos( Glib::ustring basePath,
Util::IOSerialize& ser ) const
{
bool result = true;
int i = 0;
for ( FormatInfoVector::const_iterator it = m_formatInfos.begin();
it != m_formatInfos.end();
++it )
{
const FormatInfo& info = *it;
std::ostringstream strstrm;
strstrm << basePath << i;
result &= ser.write( strstrm.str() + "/m_samplingFrequency", info.m_samplingFrequency );
result &= ser.write( strstrm.str() + "/m_isSyncStream", info.m_isSyncStream );
result &= ser.write( strstrm.str() + "/m_audioChannels", info.m_audioChannels );
result &= ser.write( strstrm.str() + "/m_midiChannels", info.m_midiChannels );
result &= ser.write( strstrm.str() + "/m_index", info.m_index );
i++;
}
return result;
}
bool
Plug::deserializeFormatInfos( Glib::ustring basePath,
Util::IODeserialize& deser )
{
int i = 0;
bool bFinished = false;
bool result = true;
do {
std::ostringstream strstrm;
strstrm << basePath << i;
// check for one element to exist. when one exist the other elements
// must also be there. otherwise just return (last) result.
if ( deser.isExisting( strstrm.str() + "/m_samplingFrequency" ) ) {
FormatInfo info;
result &= deser.read( strstrm.str() + "/m_samplingFrequency", info.m_samplingFrequency );
result &= deser.read( strstrm.str() + "/m_isSyncStream", info.m_isSyncStream );
result &= deser.read( strstrm.str() + "/m_audioChannels", info.m_audioChannels );
result &= deser.read( strstrm.str() + "/m_midiChannels", info.m_midiChannels );
result &= deser.read( strstrm.str() + "/m_index", info.m_index );
if ( result ) {
m_formatInfos.push_back( info );
i++;
} else {
bFinished = true;
}
} else {
bFinished = true;
}
} while ( !bFinished );
return result;
}
bool
Plug::serialize( Glib::ustring basePath, Util::IOSerialize& ser ) const
{
bool result=true;
result &= ser.write( basePath + "m_subunitType", getSubunitType());
result &= ser.write( basePath + "m_subunitId", getSubunitId());
result &= ser.write( basePath + "m_functionBlockType", m_functionBlockType);
result &= ser.write( basePath + "m_functionBlockId", m_functionBlockId);
result &= ser.write( basePath + "m_addressType", m_addressType );
result &= ser.write( basePath + "m_direction", m_direction);
result &= ser.write( basePath + "m_id", m_id);
result &= ser.write( basePath + "m_infoPlugType", m_infoPlugType);
result &= ser.write( basePath + "m_nrOfChannels", m_nrOfChannels);
result &= ser.write( basePath + "m_name", m_name);
result &= serializeClusterInfos( basePath + "m_clusterInfos", ser );
result &= ser.write( basePath + "m_samplingFrequency", m_samplingFrequency);
result &= serializeFormatInfos( basePath + "m_formatInfo", ser );
result &= serializePlugVector( basePath + "m_inputConnections", ser, m_inputConnections );
result &= serializePlugVector( basePath + "m_outputConnections", ser, m_outputConnections );
result &= ser.write( basePath + "m_globalId", m_globalId);
result &= ser.write( basePath + "m_globalIdCounter", m_globalIdCounter );
return result;
}
Plug*
Plug::deserialize( Glib::ustring basePath,
Util::IODeserialize& deser,
Unit& unit,
PlugManager& plugManager )
{
ESubunitType subunitType;
subunit_t subunitId;
function_block_type_t functionBlockType;
function_block_id_t functionBlockId;
EPlugAddressType addressType;
EPlugDirection direction;
plug_id_t id;
if ( !deser.isExisting( basePath + "m_subunitType" ) ) {
return 0;
}
bool result=true;
result = deser.read( basePath + "m_subunitType", subunitType );
result &= deser.read( basePath + "m_subunitId", subunitId );
Subunit* subunit = unit.getSubunit( subunitType, subunitId );
result &= deser.read( basePath + "m_functionBlockType", functionBlockType );
result &= deser.read( basePath + "m_functionBlockId", functionBlockId );
result &= deser.read( basePath + "m_addressType", addressType );
result &= deser.read( basePath + "m_direction", direction );
result &= deser.read( basePath + "m_id", id );
Plug* pPlug = unit.createPlug( &unit, subunit, functionBlockType,
functionBlockId, addressType, direction, id);
if ( !pPlug ) {
return 0;
}
result &= deser.read( basePath + "m_infoPlugType", pPlug->m_infoPlugType );
result &= deser.read( basePath + "m_nrOfChannels", pPlug->m_nrOfChannels );
result &= deser.read( basePath + "m_name", pPlug->m_name );
result &= pPlug->deserializeClusterInfos( basePath + "m_clusterInfos", deser );
result &= deser.read( basePath + "m_samplingFrequency", pPlug->m_samplingFrequency );
result &= pPlug->deserializeFormatInfos( basePath + "m_formatInfos", deser );
// input and output connections can't be processed here because not all plugs might
// deserialized at this point. so we do that in deserializeUpdate.
result &= deser.read( basePath + "m_globalId", pPlug->m_globalId );
result &= deser.read( basePath + "m_globalIdCounter", pPlug->m_globalIdCounter );
if ( !result ) {
delete pPlug;
return 0;
}
return pPlug;
}
bool
Plug::deserializeConnections( Glib::ustring basePath,
Util::IODeserialize& deser )
{
bool result;
result = deserializePlugVector( basePath + "/m_inputConnections", deser,
m_unit->getPlugManager(), m_inputConnections );
result &= deserializePlugVector( basePath + "/m_outputConnections", deser,
m_unit->getPlugManager(), m_outputConnections );
return result;
}
bool
Plug::deserializeUpdateSubunit()
{
m_subunit = m_unit->getSubunit( m_subunitType, m_subunitId );
return true;
}
/////////////////////////////////////////
/////////////////////////////////////////
const char* avPlugAddressTypeStrings[] =
{
"PCR",
"external",
"asynchronous",
"subunit",
"functionblock",
"undefined",
};
const char* avPlugAddressTypeToString( Plug::EPlugAddressType type )
{
if ( type > ( int )( sizeof( avPlugAddressTypeStrings )
/ sizeof( avPlugAddressTypeStrings[0] ) ) )
{
type = Plug::eAPA_Undefined;
}
return avPlugAddressTypeStrings[type];
}
const char* avPlugTypeStrings[] =
{
"IsoStream",
"AsyncStream",
"MIDI",
"Sync",
"Analog",
"Digital",
"Unknown",
};
const char* avPlugTypeToString( Plug::EPlugType type )
{
if ( type > ( int )( sizeof( avPlugTypeStrings )
/ sizeof( avPlugTypeStrings[0] ) ) )
{
type = Plug::eAPT_Unknown;
}
return avPlugTypeStrings[type];
}
const char* avPlugDirectionStrings[] =
{
"Input",
"Output",
"Unknown",
};
const char* avPlugDirectionToString( Plug::EPlugDirection type )
{
if ( type > ( int )( sizeof( avPlugDirectionStrings )
/ sizeof( avPlugDirectionStrings[0] ) ) )
{
type = Plug::eAPD_Unknown;
}
return avPlugDirectionStrings[type];
}
/////////////////////////////////////
PlugManager::PlugManager( )
{
}
PlugManager::PlugManager( const PlugManager& rhs )
{
setDebugLevel( rhs.getDebugLevel() );
}
PlugManager::~PlugManager()
{
}
void
PlugManager::setVerboseLevel( int l )
{
setDebugLevel(l);
for ( PlugVector::iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
(*it)->setVerboseLevel(l);
}
debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
}
bool
PlugManager::addPlug( Plug& plug )
{
m_plugs.push_back( &plug );
// inherit debug level
plug.setVerboseLevel(getDebugLevel());
return true;
}
bool
PlugManager::remPlug( Plug& plug )
{
for ( PlugVector::iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* plugIt = *it;
if ( plugIt == &plug ) {
m_plugs.erase( it );
return true;
}
}
return false;
}
// helper function
static void addConnection( PlugConnectionVector& connections,
Plug& srcPlug,
Plug& destPlug )
{
for ( PlugConnectionVector::iterator it = connections.begin();
it != connections.end();
++it )
{
PlugConnection* con = *it;
if ( ( &( con->getSrcPlug() ) == &srcPlug )
&& ( &( con->getDestPlug() ) == &destPlug ) )
{
return;
}
}
connections.push_back( new PlugConnection( srcPlug, destPlug ) );
}
bool
PlugManager::tidyPlugConnections(PlugConnectionVector& connections)
{
for ( PlugVector::const_iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* plug = *it;
for ( PlugVector::const_iterator it =
plug->getInputConnections().begin();
it != plug->getInputConnections().end();
++it )
{
addConnection( connections, *( *it ), *plug );
}
plug->getInputConnections().clear();
for ( PlugVector::const_iterator it =
plug->getOutputConnections().begin();
it != plug->getOutputConnections().end();
++it )
{
addConnection( connections, *plug, *( *it ) );
}
plug->getOutputConnections().clear();
}
for ( PlugConnectionVector::iterator it = connections.begin();
it != connections.end();
++it )
{
PlugConnection * con = *it;
con->getSrcPlug().getOutputConnections().push_back(&( con->getDestPlug() ));
con->getDestPlug().getInputConnections().push_back(&( con->getSrcPlug() ));
}
return true;
}
static void addConnectionOwner( PlugConnectionOwnerVector& connections,
Plug& srcPlug,
Plug& destPlug )
{
for ( PlugConnectionOwnerVector::iterator it = connections.begin();
it != connections.end();
++it )
{
PlugConnection& con = *it;
if ( ( &( con.getSrcPlug() ) == &srcPlug )
&& ( &( con.getDestPlug() ) == &destPlug ) )
{
return;
}
}
connections.push_back( PlugConnection( srcPlug, destPlug ) );
}
void
PlugManager::showPlugs() const
{
if(getDebugLevel() < DEBUG_LEVEL_INFO) return;
// \todo The information provided here could be better arranged. For a start it is ok, but
// there is room for improvement. Something for a lazy sunday afternoon (tip: maybe drink some
// beer to get into the mood)
printf( "\nSummary\n" );
printf( "-------\n\n" );
printf( "Nr | AddressType | Direction | SubUnitType | SubUnitId | FunctionBlockType | FunctionBlockId | Id | Type |Name\n" );
printf( "---+-----------------+-----------+-------------+-----------+-------------------+-----------------+------+--------------+------\n" );
for ( PlugVector::const_iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* plug = *it;
printf( "%2d | %15s | %9s | %11s | 0x%02x | 0x%02x | 0x%02x | 0x%02x | %12s | %s\n",
plug->getGlobalId(),
avPlugAddressTypeToString( plug->getPlugAddressType() ),
avPlugDirectionToString( plug->getDirection() ),
subunitTypeToString( plug->getSubunitType() ),
plug->getSubunitId(),
plug->getFunctionBlockType(),
plug->getFunctionBlockId(),
plug->getPlugId(),
avPlugTypeToString( plug->getPlugType() ),
plug->getName() );
}
printf( "\nConnections\n" );
printf( "-----------\n" );
PlugConnectionOwnerVector connections;
for ( PlugVector::const_iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* plug = *it;
for ( PlugVector::const_iterator it =
plug->getInputConnections().begin();
it != plug->getInputConnections().end();
++it )
{
addConnectionOwner( connections, *( *it ), *plug );
}
for ( PlugVector::const_iterator it =
plug->getOutputConnections().begin();
it != plug->getOutputConnections().end();
++it )
{
addConnectionOwner( connections, *plug, *( *it ) );
}
}
printf( "digraph avcconnections {\n" );
for ( PlugConnectionOwnerVector::iterator it = connections.begin();
it != connections.end();
++it )
{
PlugConnection& con = *it;
printf( "\t\"(%d) %s\" -> \"(%d) %s\"\n",
con.getSrcPlug().getGlobalId(),
con.getSrcPlug().getName(),
con.getDestPlug().getGlobalId(),
con.getDestPlug().getName() );
}
for ( PlugVector::const_iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* plug = *it;
if ( plug->getFunctionBlockType() != 0xff ) {
std::ostringstream strstrm;
switch(plug->getFunctionBlockType()) {
case 0x80:
strstrm << "Selector FB";
break;
case 0x81:
strstrm << "Feature FB";
break;
case 0x82:
strstrm << "Processing FB";
break;
case 0x83:
strstrm << "CODEC FB";
break;
default:
strstrm << plug->getFunctionBlockType();
}
if ( plug->getPlugDirection() == Plug::eAPD_Input ) {
printf( "\t\"(%d) %s\" -> \"(%s, ID %d)\"\n",
plug->getGlobalId(),
plug->getName(),
strstrm.str().c_str(),
plug->getFunctionBlockId() );
} else {
printf( "\t\"(%s, ID %d)\" -> \t\"(%d) %s\"\n",
strstrm.str().c_str(),
plug->getFunctionBlockId(),
plug->getGlobalId(),
plug->getName() );
}
}
}
const char* colorStrings[] = {
"coral",
"slateblue",
"white",
"green",
"yellow",
"grey",
};
for ( PlugVector::const_iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* plug = *it;
printf( "\t\"(%d) %s\" [color=%s,style=filled];\n",
plug->getGlobalId(), plug->getName(),
colorStrings[plug->getPlugAddressType() ] );
}
printf("}\n" );
printf( "Use \"dot -Tps FILENAME.dot -o FILENAME.ps\" "
"to generate graph\n");
debugOutput( DEBUG_LEVEL_VERBOSE, "Plug details\n" );
debugOutput( DEBUG_LEVEL_VERBOSE, "------------\n" );
for ( PlugVector::const_iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* plug = *it;
debugOutput( DEBUG_LEVEL_VERBOSE, "Plug %d:\n", plug->getGlobalId() );
plug->showPlug();
}
}
Plug*
PlugManager::getPlug( ESubunitType subunitType,
subunit_id_t subunitId,
function_block_type_t functionBlockType,
function_block_id_t functionBlockId,
Plug::EPlugAddressType plugAddressType,
Plug::EPlugDirection plugDirection,
plug_id_t plugId ) const
{
debugOutput( DEBUG_LEVEL_VERBOSE, "SBT, SBID, FBT, FBID, AT, PD, ID = "
"(0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x)\n",
subunitType,
subunitId,
functionBlockType,
functionBlockId,
plugAddressType,
plugDirection,
plugId );
for ( PlugVector::const_iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* plug = *it;
if ( ( subunitType == plug->getSubunitType() )
&& ( subunitId == plug->getSubunitId() )
&& ( functionBlockType == plug->getFunctionBlockType() )
&& ( functionBlockId == plug->getFunctionBlockId() )
&& ( plugAddressType == plug->getPlugAddressType() )
&& ( plugDirection == plug->getPlugDirection() )
&& ( plugId == plug->getPlugId() ) )
{
return plug;
}
}
return 0;
}
Plug*
PlugManager::getPlug( int iGlobalId ) const
{
for ( PlugVector::const_iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* pPlug = *it;
if ( pPlug->getGlobalId() == iGlobalId ) {
return pPlug;
}
}
return 0;
}
PlugVector
PlugManager::getPlugsByType( ESubunitType subunitType,
subunit_id_t subunitId,
function_block_type_t functionBlockType,
function_block_id_t functionBlockId,
Plug::EPlugAddressType plugAddressType,
Plug::EPlugDirection plugDirection,
Plug::EPlugType type) const
{
debugOutput( DEBUG_LEVEL_VERBOSE, "SBT, SBID, FBT, FBID, AT, PD, T = "
"(0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x)\n",
subunitType,
subunitId,
functionBlockType,
functionBlockId,
plugAddressType,
plugDirection,
type );
PlugVector plugVector;
for ( PlugVector::const_iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* pPlug = *it;
if ( ( subunitType == pPlug->getSubunitType() )
&& ( subunitId == pPlug->getSubunitId() )
&& ( functionBlockType == pPlug->getFunctionBlockType() )
&& ( functionBlockId == pPlug->getFunctionBlockId() )
&& ( plugAddressType == pPlug->getPlugAddressType() )
&& ( plugDirection == pPlug->getPlugDirection() )
&& ( type == pPlug->getPlugType() ) )
{
plugVector.push_back( pPlug );
}
}
return plugVector;
}
bool
PlugManager::serialize( Glib::ustring basePath, Util::IOSerialize& ser ) const
{
bool result = true;
int i = 0;
for ( PlugVector::const_iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* pPlug = *it;
std::ostringstream strstrm;
strstrm << basePath << i;
result &= pPlug->serialize( strstrm.str() + "/", ser );
i++;
}
return result;
}
PlugManager*
PlugManager::deserialize( Glib::ustring basePath,
Util::IODeserialize& deser,
Unit& unit )
{
PlugManager* pMgr = new PlugManager;
if ( !pMgr ) {
return 0;
}
int i = 0;
Plug* pPlug = 0;
do {
std::ostringstream strstrm;
strstrm << basePath << i;
// unit still holds a null pointer for the plug manager
// therefore we have to *this as additional argument
pPlug = Plug::deserialize( strstrm.str() + "/",
deser,
unit,
*pMgr );
if ( pPlug ) {
pMgr->m_plugs.push_back( pPlug );
i++;
}
} while ( pPlug );
return pMgr;
}
bool
PlugManager::deserializeUpdate( Glib::ustring basePath,
Util::IODeserialize& deser)
{
bool result = true;
for ( PlugVector::const_iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
Plug* pPlug = *it;
std::ostringstream strstrm;
strstrm << basePath << "Plug" << pPlug->getGlobalId();
result &= pPlug->deserializeConnections( strstrm.str(), deser );
result &= pPlug->deserializeUpdateSubunit();
}
return result;
}
////////////////////////////////////
PlugConnection::PlugConnection( Plug& srcPlug, Plug& destPlug )
: m_srcPlug( &srcPlug )
, m_destPlug( &destPlug )
{
}
PlugConnection::PlugConnection()
: m_srcPlug( 0 )
, m_destPlug( 0 )
{
}
bool
PlugConnection::serialize( Glib::ustring basePath, Util::IOSerialize& ser ) const
{
bool result;
result = ser.write( basePath + "m_srcPlug", m_srcPlug->getGlobalId() );
result &= ser.write( basePath + "m_destPlug", m_destPlug->getGlobalId() );
return result;
}
PlugConnection*
PlugConnection::deserialize( Glib::ustring basePath,
Util::IODeserialize& deser,
Unit& unit )
{
if ( !deser.isExisting( basePath + "m_srcPlug" ) ) {
return 0;
}
PlugConnection* pConnection = new PlugConnection;
if ( !pConnection ) {
return 0;
}
bool result;
int iSrcPlugId;
int iDestPlugId;
result = deser.read( basePath + "m_srcPlug", iSrcPlugId );
result &= deser.read( basePath + "m_destPlug", iDestPlugId );
if ( !result ) {
delete pConnection;
return 0;
}
pConnection->m_srcPlug = unit.getPlugManager().getPlug( iSrcPlugId );
pConnection->m_destPlug = unit.getPlugManager().getPlug( iDestPlugId );
if ( !pConnection->m_srcPlug || !pConnection->m_destPlug ) {
delete pConnection;
return 0;
}
return pConnection;
}
ExtendedStreamFormatCmd
Plug::setPlugAddrToStreamFormatCmd(
ExtendedStreamFormatCmd::ESubFunction subFunction)
{
ExtendedStreamFormatCmd extStreamFormatInfoCmd(
m_unit->get1394Service(),
subFunction );
switch( getSubunitType() ) {
case eST_Unit:
{
UnitPlugAddress::EPlugType ePlugType =
UnitPlugAddress::ePT_Unknown;
switch ( m_addressType ) {
case eAPA_PCR:
ePlugType = UnitPlugAddress::ePT_PCR;
break;
case eAPA_ExternalPlug:
ePlugType = UnitPlugAddress::ePT_ExternalPlug;
break;
case eAPA_AsynchronousPlug:
ePlugType = UnitPlugAddress::ePT_AsynchronousPlug;
break;
default:
ePlugType = UnitPlugAddress::ePT_Unknown;
}
UnitPlugAddress unitPlugAddress( ePlugType,
m_id );
extStreamFormatInfoCmd.setPlugAddress(
PlugAddress( convertPlugDirection( getPlugDirection() ),
PlugAddress::ePAM_Unit,
unitPlugAddress ) );
}
break;
case eST_Music:
case eST_Audio:
{
switch( m_addressType ) {
case eAPA_SubunitPlug:
{
SubunitPlugAddress subunitPlugAddress( m_id );
extStreamFormatInfoCmd.setPlugAddress(
PlugAddress( convertPlugDirection( getPlugDirection() ),
PlugAddress::ePAM_Subunit,
subunitPlugAddress ) );
}
break;
case eAPA_FunctionBlockPlug:
{
FunctionBlockPlugAddress functionBlockPlugAddress(
m_functionBlockType,
m_functionBlockId,
m_id );
extStreamFormatInfoCmd.setPlugAddress(
PlugAddress( convertPlugDirection( getPlugDirection() ),
PlugAddress::ePAM_FunctionBlock,
functionBlockPlugAddress ) );
}
break;
default:
extStreamFormatInfoCmd.setPlugAddress(PlugAddress());
}
}
break;
default:
debugError( "Unknown subunit type\n" );
}
extStreamFormatInfoCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
extStreamFormatInfoCmd.setCommandType( AVCCommand::eCT_Status );
extStreamFormatInfoCmd.setSubunitId( getSubunitId() );
extStreamFormatInfoCmd.setSubunitType( getSubunitType() );
return extStreamFormatInfoCmd;
}
bool
serializePlugVector( Glib::ustring basePath,
Util::IOSerialize& ser,
const PlugVector& vec)
{
bool result = true;
int i = 0;
for ( PlugVector::const_iterator it = vec.begin();
it != vec.end();
++it )
{
const Plug* pPlug = *it;
std::ostringstream strstrm;
strstrm << basePath << i;
result &= ser.write( strstrm.str() + "/global_id", pPlug->getGlobalId() );
i++;
}
return result;
}
bool
deserializePlugVector( Glib::ustring basePath,
Util::IODeserialize& deser,
const PlugManager& plugManager,
PlugVector& vec )
{
int i = 0;
Plug* pPlug = 0;
do {
std::ostringstream strstrm;
unsigned int iPlugId;
strstrm << basePath << i;
if ( !deser.isExisting( strstrm.str() + "/global_id" ) ) {
// no more plugs found, so this is the normal return point
return true;
}
if ( !deser.read( strstrm.str() + "/global_id", iPlugId ) ) {
return false;
}
pPlug = plugManager.getPlug( iPlugId );
if ( pPlug ) {
vec.push_back( pPlug );
i++;
}
} while ( pPlug );
// if we reach here, the plug manager didn't find any plug with the id iPlugId.
return false;
}
}