/* * Copyright (C) 2005-2007 by Pieter Palmers * Copyright (C) 2005-2007 by Daniel Wagner * * This file is part of FFADO * FFADO = Free Firewire (pro-)audio drivers for linux * * FFADO is based upon FreeBoB. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation; * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #warning Generic AV/C support is currently useless #include "genericavc/avc_avdevice.h" #include "libieee1394/configrom.h" #include "libieee1394/ieee1394service.h" #include "libavc/avc_definitions.h" #include "libavc/general/avc_plug_info.h" #include "debugmodule/debugmodule.h" #include #include #include #include #include #include #include using namespace AVC; namespace GenericAVC { IMPL_DEBUG_MODULE( AvDevice, AvDevice, DEBUG_LEVEL_VERBOSE ); // to define the supported devices static VendorModelEntry supportedDeviceList[] = { {0x001486, 0x00000af2, "Echo", "AudioFire2"}, }; AvDevice::AvDevice( std::auto_ptr< ConfigRom >( configRom ), Ieee1394Service& ieee1394service, int nodeId ) : FFADODevice( configRom, ieee1394service, nodeId ) , m_model( NULL ) { debugOutput( DEBUG_LEVEL_VERBOSE, "Created GenericAVC::AvDevice (NodeID %d)\n", nodeId ); addOption(Util::OptionContainer::Option("snoopMode",false)); } AvDevice::~AvDevice() { } bool AvDevice::probe( ConfigRom& configRom ) { unsigned int vendorId = configRom.getNodeVendorId(); unsigned int modelId = configRom.getModelId(); for ( unsigned int i = 0; i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) ); ++i ) { if ( ( supportedDeviceList[i].vendor_id == vendorId ) && ( supportedDeviceList[i].model_id == modelId ) ) { return true; } } return false; } bool AvDevice::discover() { unsigned int vendorId = m_pConfigRom->getNodeVendorId(); unsigned int modelId = m_pConfigRom->getModelId(); for ( unsigned int i = 0; i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) ); ++i ) { if ( ( supportedDeviceList[i].vendor_id == vendorId ) && ( supportedDeviceList[i].model_id == modelId ) ) { m_model = &(supportedDeviceList[i]); } } if (m_model == NULL) { return false; } debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n", m_model->vendor_name, m_model->model_name); if ( !Unit::discover() ) { debugError( "Could not discover unit\n" ); return false; } if((getAudioSubunit( 0 ) == NULL)) { debugError( "Unit doesn't have an Audio subunit.\n"); return false; } if((getMusicSubunit( 0 ) == NULL)) { debugError( "Unit doesn't have a Music subunit.\n"); return false; } return true; } void AvDevice::setVerboseLevel(int l) { m_pPlugManager->setVerboseLevel(l); FFADODevice::setVerboseLevel(l); AVC::Unit::setVerboseLevel(l); } int AvDevice::getSamplingFrequency( ) { AVC::Plug* inputPlug = getPlugById( m_pcrPlugs, Plug::eAPD_Input, 0 ); if ( !inputPlug ) { debugError( "setSampleRate: Could not retrieve iso input plug 0\n" ); return false; } AVC::Plug* outputPlug = getPlugById( m_pcrPlugs, Plug::eAPD_Output, 0 ); if ( !outputPlug ) { debugError( "setSampleRate: Could not retrieve iso output plug 0\n" ); return false; } int samplerate_playback=inputPlug->getSampleRate(); int samplerate_capture=outputPlug->getSampleRate(); if (samplerate_playback != samplerate_capture) { debugWarning("Samplerates for capture and playback differ!\n"); } return samplerate_capture; } bool AvDevice::setSamplingFrequency( int s ) { bool snoopMode=false; if(!getOption("snoopMode", snoopMode)) { debugWarning("Could not retrieve snoopMode parameter, defauling to false\n"); } if(snoopMode) { int current_sr=getSamplingFrequency(); if (current_sr != s ) { debugError("In snoop mode it is impossible to set the sample rate.\n"); debugError("Please start the client with the correct setting.\n"); return false; } return true; } else { AVC::Plug* plug = getPlugById( m_pcrPlugs, Plug::eAPD_Input, 0 ); if ( !plug ) { debugError( "setSampleRate: Could not retrieve iso input plug 0\n" ); return false; } if ( !plug->setSampleRate( s ) ) { debugError( "setSampleRate: Setting sample rate failed\n" ); return false; } plug = getPlugById( m_pcrPlugs, Plug::eAPD_Output, 0 ); if ( !plug ) { debugError( "setSampleRate: Could not retrieve iso output plug 0\n" ); return false; } if ( !plug->setSampleRate( s ) ) { debugError( "setSampleRate: Setting sample rate failed\n" ); return false; } debugOutput( DEBUG_LEVEL_VERBOSE, "setSampleRate: Set sample rate to %d\n", s ); return true; } // not executable return false; } bool AvDevice::lock() { bool snoopMode=false; if(!getOption("snoopMode", snoopMode)) { debugWarning("Could not retrieve snoopMode parameter, defauling to false\n"); } if (snoopMode) { // don't lock } else { // return Unit::reserve(4); } return true; } bool AvDevice::unlock() { bool snoopMode=false; if(!getOption("snoopMode", snoopMode)) { debugWarning("Could not retrieve snoopMode parameter, defauling to false\n"); } if (snoopMode) { // don't unlock } else { // return Unit::reserve(0); } return true; } void AvDevice::showDevice() { debugOutput(DEBUG_LEVEL_VERBOSE, "%s %s at node %d\n", m_model->vendor_name, m_model->model_name, m_nodeId); m_pPlugManager->showPlugs(); flushDebugOutput(); } bool AvDevice::prepare() { bool snoopMode=false; if(!getOption("snoopMode", snoopMode)) { debugWarning("Could not retrieve snoopMode parameter, defauling to false\n"); } /////////// // get plugs AVC::Plug* inputPlug = getPlugById( m_pcrPlugs, Plug::eAPD_Input, 0 ); if ( !inputPlug ) { debugError( "setSampleRate: Could not retrieve iso input plug 0\n" ); return false; } AVC::Plug* outputPlug = getPlugById( m_pcrPlugs, Plug::eAPD_Output, 0 ); if ( !outputPlug ) { debugError( "setSampleRate: Could not retrieve iso output plug 0\n" ); return false; } int samplerate=outputPlug->getSampleRate(); debugOutput( DEBUG_LEVEL_VERBOSE, "Initializing receive processor...\n"); // create & add streamprocessors Streaming::StreamProcessor *p; p=new Streaming::AmdtpReceiveStreamProcessor( get1394Service().getPort(), samplerate, outputPlug->getNrOfChannels()); if(!p->init()) { debugFatal("Could not initialize receive processor!\n"); delete p; return false; } if (!addPlugToProcessor(*outputPlug,p, Streaming::Port::E_Capture)) { debugFatal("Could not add plug to processor!\n"); delete p; return false; } m_receiveProcessors.push_back(p); // do the transmit processor debugOutput( DEBUG_LEVEL_VERBOSE, "Initializing transmit processor%s...\n", (snoopMode?" in snoop mode":"")); if (snoopMode) { // we are snooping, so this is receive too. p=new Streaming::AmdtpReceiveStreamProcessor( get1394Service().getPort(), samplerate, inputPlug->getNrOfChannels()); } else { p=new Streaming::AmdtpTransmitStreamProcessor( get1394Service().getPort(), samplerate, inputPlug->getNrOfChannels()); } if(!p->init()) { debugFatal("Could not initialize transmit processor %s!\n", (snoopMode?" in snoop mode":"")); delete p; return false; } if (snoopMode) { if (!addPlugToProcessor(*inputPlug,p, Streaming::Port::E_Capture)) { debugFatal("Could not add plug to processor!\n"); return false; } } else { if (!addPlugToProcessor(*inputPlug,p, Streaming::Port::E_Playback)) { debugFatal("Could not add plug to processor!\n"); return false; } } // we put this SP into the transmit SP vector, // no matter if we are in snoop mode or not // this allows us to find out what direction // a certain stream should have. m_transmitProcessors.push_back(p); return true; } bool AvDevice::addPlugToProcessor( AVC::Plug& plug, Streaming::StreamProcessor *processor, Streaming::AmdtpAudioPort::E_Direction direction) { std::string id=std::string("dev?"); if(!getOption("id", id)) { debugWarning("Could not retrieve id parameter, defauling to 'dev?'\n"); } Plug::ClusterInfoVector& clusterInfos = plug.getClusterInfos(); for ( Plug::ClusterInfoVector::const_iterator it = clusterInfos.begin(); it != clusterInfos.end(); ++it ) { const Plug::ClusterInfo* clusterInfo = &( *it ); Plug::ChannelInfoVector channelInfos = clusterInfo->m_channelInfos; for ( Plug::ChannelInfoVector::const_iterator it = channelInfos.begin(); it != channelInfos.end(); ++it ) { const Plug::ChannelInfo* channelInfo = &( *it ); std::ostringstream portname; portname << id << "_" << channelInfo->m_name; Streaming::Port *p=NULL; switch(clusterInfo->m_portType) { case ExtendedPlugInfoClusterInfoSpecificData::ePT_Speaker: case ExtendedPlugInfoClusterInfoSpecificData::ePT_Headphone: case ExtendedPlugInfoClusterInfoSpecificData::ePT_Microphone: case ExtendedPlugInfoClusterInfoSpecificData::ePT_Line: case ExtendedPlugInfoClusterInfoSpecificData::ePT_Analog: debugOutput(DEBUG_LEVEL_VERBOSE, " Adding audio channel %s (pos=0x%02X, loc=0x%02X)\n", channelInfo->m_name.c_str(), channelInfo->m_streamPosition, channelInfo->m_location); p=new Streaming::AmdtpAudioPort( portname.str(), direction, channelInfo->m_streamPosition, channelInfo->m_location, Streaming::AmdtpPortInfo::E_MBLA ); break; case ExtendedPlugInfoClusterInfoSpecificData::ePT_MIDI: debugOutput(DEBUG_LEVEL_VERBOSE, " Adding MIDI channel %s (pos=0x%02X, loc=0x%02X)\n", channelInfo->m_name.c_str(), channelInfo->m_streamPosition, processor->getPortCount(Streaming::Port::E_Midi)); p=new Streaming::AmdtpMidiPort( portname.str(), direction, channelInfo->m_streamPosition, // Workaround for out-of-spec hardware // should be: // channelInfo->m_location, // but now we renumber the midi channels' location as they // are discovered processor->getPortCount(Streaming::Port::E_Midi), Streaming::AmdtpPortInfo::E_Midi ); break; case ExtendedPlugInfoClusterInfoSpecificData::ePT_SPDIF: case ExtendedPlugInfoClusterInfoSpecificData::ePT_ADAT: case ExtendedPlugInfoClusterInfoSpecificData::ePT_TDIF: case ExtendedPlugInfoClusterInfoSpecificData::ePT_MADI: case ExtendedPlugInfoClusterInfoSpecificData::ePT_Digital: debugOutput(DEBUG_LEVEL_VERBOSE, " Adding digital audio channel %s (pos=0x%02X, loc=0x%02X)\n", channelInfo->m_name.c_str(), channelInfo->m_streamPosition, channelInfo->m_location); p=new Streaming::AmdtpAudioPort( portname.str(), direction, channelInfo->m_streamPosition, channelInfo->m_location, Streaming::AmdtpPortInfo::E_MBLA ); break; case ExtendedPlugInfoClusterInfoSpecificData::ePT_NoType: default: // unsupported break; } if (!p) { debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",channelInfo->m_name.c_str()); } else { if (!processor->addPort(p)) { debugWarning("Could not register port with stream processor\n"); return false; } } } } return true; } int AvDevice::getStreamCount() { return m_receiveProcessors.size() + m_transmitProcessors.size(); } Streaming::StreamProcessor * AvDevice::getStreamProcessorByIndex(int i) { if (i<(int)m_receiveProcessors.size()) { return m_receiveProcessors.at(i); } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) { return m_transmitProcessors.at(i-m_receiveProcessors.size()); } return NULL; } bool AvDevice::startStreamByIndex(int i) { int iso_channel=-1; bool snoopMode=false; if(!getOption("snoopMode", snoopMode)) { debugWarning("Could not retrieve snoopMode parameter, defauling to false\n"); } if (i<(int)m_receiveProcessors.size()) { int n=i; Streaming::StreamProcessor *p=m_receiveProcessors.at(n); if(snoopMode) { // a stream from the device to another host // FIXME: put this into a decent framework! // we should check the oPCR[n] on the device struct iec61883_oPCR opcr; if (iec61883_get_oPCRX( get1394Service().getHandle(), m_pConfigRom->getNodeId() | 0xffc0, (quadlet_t *)&opcr, n)) { debugWarning("Error getting the channel for SP %d\n",i); return false; } iso_channel=opcr.channel; } else { iso_channel=get1394Service().allocateIsoChannelCMP( m_pConfigRom->getNodeId() | 0xffc0, n, get1394Service().getLocalNodeId()| 0xffc0, -1); } if (iso_channel<0) { debugError("Could not allocate ISO channel for SP %d\n",i); return false; } debugOutput(DEBUG_LEVEL_VERBOSE, "Started SP %d on channel %d\n",i,iso_channel); p->setChannel(iso_channel); return true; } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) { int n=i-m_receiveProcessors.size(); Streaming::StreamProcessor *p=m_transmitProcessors.at(n); if(snoopMode) { // a stream from another host to the device // FIXME: put this into a decent framework! // we should check the iPCR[n] on the device struct iec61883_iPCR ipcr; if (iec61883_get_iPCRX( get1394Service().getHandle(), m_pConfigRom->getNodeId() | 0xffc0, (quadlet_t *)&ipcr, n)) { debugWarning("Error getting the channel for SP %d\n",i); return false; } iso_channel=ipcr.channel; } else { iso_channel=get1394Service().allocateIsoChannelCMP( get1394Service().getLocalNodeId()| 0xffc0, -1, m_pConfigRom->getNodeId() | 0xffc0, n); } if (iso_channel<0) { debugError("Could not allocate ISO channel for SP %d\n",i); return false; } debugOutput(DEBUG_LEVEL_VERBOSE, "Started SP %d on channel %d\n",i,iso_channel); p->setChannel(iso_channel); return true; } debugError("SP index %d out of range!\n",i); return false; } bool AvDevice::stopStreamByIndex(int i) { bool snoopMode=false; if(!getOption("snoopMode", snoopMode)) { debugWarning("Could not retrieve snoopMode parameter, defauling to false\n"); } if (i<(int)m_receiveProcessors.size()) { int n=i; Streaming::StreamProcessor *p=m_receiveProcessors.at(n); if(snoopMode) { } else { // deallocate ISO channel if(!get1394Service().freeIsoChannel(p->getChannel())) { debugError("Could not deallocate iso channel for SP %d\n",i); return false; } } p->setChannel(-1); return true; } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) { int n=i-m_receiveProcessors.size(); Streaming::StreamProcessor *p=m_transmitProcessors.at(n); if(snoopMode) { } else { // deallocate ISO channel if(!get1394Service().freeIsoChannel(p->getChannel())) { debugError("Could not deallocate iso channel for SP %d\n",i); return false; } } p->setChannel(-1); return true; } debugError("SP index %d out of range!\n",i); return false; } }