Index: trunk/libffado/src/libieee1394/IsoHandlerManager.cpp =================================================================== --- trunk/libffado/src/libieee1394/IsoHandlerManager.cpp (revision 807) +++ trunk/libffado/src/libieee1394/IsoHandlerManager.cpp (revision 833) @@ -378,5 +378,5 @@ } - max_packet_size = page_size; + //max_packet_size = page_size; // HACK unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD; if(irq_interval <= 0) irq_interval=1; @@ -395,4 +395,5 @@ return false; } + } else { debugFatal("Bad stream type\n"); Index: trunk/libffado/src/libieee1394/IsoHandler.cpp =================================================================== --- trunk/libffado/src/libieee1394/IsoHandler.cpp (revision 807) +++ trunk/libffado/src/libieee1394/IsoHandler.cpp (revision 833) @@ -174,8 +174,8 @@ IsoHandler::waitForClient() { - debugOutput(DEBUG_LEVEL_VERBOSE, "waiting...\n"); + //debugOutput(DEBUG_LEVEL_VERBOSE, "waiting...\n"); if(m_Client) { bool result = m_Client->waitForSignal(); - debugOutput(DEBUG_LEVEL_VERBOSE, " returns %d\n", result); + //debugOutput(DEBUG_LEVEL_VERBOSE, " returns %d\n", result); return result; } else { @@ -188,8 +188,8 @@ IsoHandler::tryWaitForClient() { - debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "waiting...\n"); + //debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "waiting...\n"); if(m_Client) { bool result = m_Client->tryWaitForSignal(); - debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " returns %d\n", result); + //debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " returns %d\n", result); return result; } else { @@ -214,7 +214,7 @@ // wait for the availability of frames in the client // (blocking for transmit handlers) -#ifdef DEBUG +#if 0 //#ifdef DEBUG if (getType() == eHT_Transmit) { - debugOutput(DEBUG_LEVEL_VERBOSE, "(%p) Waiting for Client to signal frame availability...\n", this); + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "(%p) Waiting for Client to signal frame availability...\n", this); } #endif @@ -222,46 +222,43 @@ #if ISOHANDLER_USE_POLL - uint64_t poll_enter = m_manager.get1394Service().getCurrentTimeAsUsecs(); - err = poll(&m_poll_fd, 1, m_poll_timeout); - uint64_t poll_exit = m_manager.get1394Service().getCurrentTimeAsUsecs(); - if (err == -1) { - if (errno == EINTR) { - return true; - } - debugFatal("%p, poll error: %s\n", this, strerror (errno)); - return false; - } - uint64_t iter_enter=0; - uint64_t iter_exit=0; - if(m_poll_fd.revents & (POLLIN)) { - iter_enter = m_manager.get1394Service().getCurrentTimeAsUsecs(); - if(!iterate()) { - debugOutput( DEBUG_LEVEL_VERBOSE, - "IsoHandler (%p): Failed to iterate handler\n", - this); + bool result = true; + while(result && m_Client && m_Client->canProcessPackets()) { + int err = poll(&m_poll_fd, 1, m_poll_timeout); + if (err == -1) { + if (errno == EINTR) { + return true; + } + debugFatal("%p, poll error: %s\n", this, strerror (errno)); return false; } - iter_exit = m_manager.get1394Service().getCurrentTimeAsUsecs(); - } else { - if (m_poll_fd.revents & POLLERR) { - debugWarning("error on fd for %p\n", this); + + if(m_poll_fd.revents & (POLLIN)) { + result=iterate(); + if(!result) { + debugOutput( DEBUG_LEVEL_VERBOSE, + "IsoHandler (%p): Failed to iterate handler\n", + this); + } + } else { + if (m_poll_fd.revents & POLLERR) { + debugWarning("error on fd for %p\n", this); + } + if (m_poll_fd.revents & POLLHUP) { + debugWarning("hangup on fd for %p\n",this); + } + break; } - if (m_poll_fd.revents & POLLHUP) { - debugWarning("hangup on fd for %p\n",this); - } - } - debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "(%c %p) poll took %lldus, iterate took %lldus\n", - (getType()==eHT_Receive?'R':'X'), this, - poll_exit-poll_enter, iter_exit-iter_enter); - return true; + } + return result; #else - // iterate blocks if no 1394 data is available + // iterate() is blocking if no 1394 data is available // so poll'ing is not really necessary - bool result = true; - while(result && m_Client->canProcessPackets()) { + while(result && m_Client && m_Client->canProcessPackets()) { result = iterate(); - debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) Iterate returned: %d\n", - this, (m_type==eHT_Receive?"Receive":"Transmit"), result); +// if (getType() == eHT_Receive) { +// debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "(%p, %s) Iterate returned: %d\n", +// this, (m_type==eHT_Receive?"Receive":"Transmit"), result); +// } } return result; @@ -275,6 +272,8 @@ bool IsoHandler::iterate() { - debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) Iterating ISO handler\n", - this, (m_type==eHT_Receive?"Receive":"Transmit")); +// if(m_type==eHT_Receive) { +// debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) Iterating ISO handler\n", +// this, (m_type==eHT_Receive?"Receive":"Transmit")); +// } if(m_State == E_Running) { #if ISOHANDLER_FLUSH_BEFORE_ITERATE @@ -282,9 +281,10 @@ #endif if(raw1394_loop_iterate(m_handle)) { - debugOutput( DEBUG_LEVEL_VERBOSE, - "IsoHandler (%p): Failed to iterate handler: %s\n", + debugError( "IsoHandler (%p): Failed to iterate handler: %s\n", this, strerror(errno)); return false; } +// debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) done iterating ISO handler\n", +// this, (m_type==eHT_Receive?"Receive":"Transmit")); return true; } else { Index: trunk/libffado/src/devicemanager.h =================================================================== --- trunk/libffado/src/devicemanager.h (revision 826) +++ trunk/libffado/src/devicemanager.h (revision 833) @@ -61,4 +61,10 @@ { public: + enum eWaitResult { + eWR_OK, + eWR_Xrun, + eWR_Error, + }; + DeviceManager(); ~DeviceManager(); @@ -79,5 +85,5 @@ bool stopStreaming(); bool resetStreaming(); - bool waitForPeriod(); + enum eWaitResult waitForPeriod(); bool setStreamingParams(unsigned int period, unsigned int rate, unsigned int nb_buffers); Index: trunk/libffado/src/libstreaming/motu/MotuPort.h =================================================================== --- trunk/libffado/src/libstreaming/motu/MotuPort.h (revision 742) +++ trunk/libffado/src/libstreaming/motu/MotuPort.h (revision 833) @@ -48,16 +48,14 @@ public: - MotuAudioPort(std::string name, - enum E_Direction direction, - int position, - int size) - : AudioPort(name, direction), + MotuAudioPort(PortManager &m, + std::string name, + enum E_Direction direction, + int position, + int size) + : AudioPort(m, name, direction), MotuPortInfo( position, size) // TODO: add more port information parameters here if nescessary {}; virtual ~MotuAudioPort() {}; - -protected: - }; @@ -73,16 +71,13 @@ public: - MotuMidiPort(std::string name, - enum E_Direction direction, - int position) - : MidiPort(name, direction), + MotuMidiPort(PortManager &m, + std::string name, + enum E_Direction direction, + int position) + : MidiPort(m, name, direction), MotuPortInfo(position, 0) // TODO: add more port information parameters here if nescessary {}; - virtual ~MotuMidiPort() {}; - -protected: - }; @@ -98,16 +93,13 @@ public: - MotuControlPort(std::string name, - enum E_Direction direction, - int position) - : ControlPort(name, direction), + MotuControlPort(PortManager &m, + std::string name, + enum E_Direction direction, + int position) + : ControlPort(m, name, direction), MotuPortInfo(position, 2) // TODO: add more port information parameters here if nescessary {}; - virtual ~MotuControlPort() {}; - -protected: - }; Index: trunk/libffado/src/libstreaming/motu/MotuTransmitStreamProcessor.cpp =================================================================== --- trunk/libffado/src/libstreaming/motu/MotuTransmitStreamProcessor.cpp (revision 798) +++ trunk/libffado/src/libstreaming/motu/MotuTransmitStreamProcessor.cpp (revision 833) @@ -62,5 +62,4 @@ {} - unsigned int MotuTransmitStreamProcessor::getMaxPacketSize() { @@ -310,18 +309,4 @@ } - // Process all ports that should be handled on a per-packet base - // this is MIDI for AMDTP (due to the need of DBC, which is lost - // when putting the events in the ringbuffer) - // for motu this might also be control data, however as control - // data isn't time specific I would also include it in the period - // based processing - - // FIXME: m_tx_dbc probably needs to be initialised to a non-zero - // value somehow so MIDI sync is possible. For now we ignore - // this issue. - if (!encodePacketPorts((quadlet_t *)(data+8), n_events, m_tx_dbc)) { - debugWarning("Problem encoding Packet Ports\n"); - } - return eCRV_OK; } @@ -403,34 +388,4 @@ { debugOutput ( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this ); - - -#if 0 - for ( PortVectorIterator it = m_Ports.begin(); - it != m_Ports.end(); - ++it ) - { - if ( ( *it )->getPortType() == Port::E_Midi ) - { - // we use a timing unit of 10ns - // this makes sure that for the max syt interval - // we don't have rounding, and keeps the numbers low - // we have 1 slot every 8 events - // we have syt_interval events per packet - // => syt_interval/8 slots per packet - // packet rate is 8000pkt/sec => interval=125us - // so the slot interval is (1/8000)/(syt_interval/8) - // or: 1/(1000 * syt_interval) sec - // which is 1e9/(1000*syt_interval) nsec - // or 100000/syt_interval 'units' - // the event interval is fixed to 320us = 32000 'units' - if ( ! ( *it )->useRateControl ( true, ( 100000/m_syt_interval ),32000, false ) ) - { - debugFatal ( "Could not set signal type to PeriodSignalling" ); - return false; - } - break; - } - } -#endif return true; } @@ -450,12 +405,11 @@ } - for ( PortVectorIterator it = m_PeriodPorts.begin(); - it != m_PeriodPorts.end(); + for ( PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); ++it ) { // If this port is disabled, don't process it if((*it)->isDisabled()) {continue;}; - //FIXME: make this into a static_cast when not DEBUG? - Port *port=dynamic_cast(*it); + Port *port=(*it); switch(port->getPortType()) { @@ -463,12 +417,14 @@ case Port::E_Audio: if (encodePortToMotuEvents(static_cast(*it), (quadlet_t *)data, offset, nevents)) { - debugWarning("Could not encode port %s to MBLA events",(*it)->getName().c_str()); + debugWarning("Could not encode port %s to Motu events",(*it)->getName().c_str()); no_problem=false; } break; - // midi is a packet based port, don't process - // case MotuPortInfo::E_Midi: - // break; - + case Port::E_Midi: +// if (encodePortToMotuMidiEvents(static_cast(*it), (quadlet_t *)data, offset, nevents)) { +// debugWarning("Could not encode port %s to Midi events",(*it)->getName().c_str()); +// no_problem=false; +// } + break; default: // ignore break; @@ -484,9 +440,8 @@ // doesn't read from the port buffers. bool no_problem = true; - for ( PortVectorIterator it = m_PeriodPorts.begin(); - it != m_PeriodPorts.end(); + for ( PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); ++it ) { - //FIXME: make this into a static_cast when not DEBUG? - Port *port=dynamic_cast(*it); + Port *port=(*it); switch(port->getPortType()) { @@ -498,8 +453,10 @@ } break; - // midi is a packet based port, don't process - // case MotuPortInfo::E_Midi: - // break; - + case Port::E_Midi: +// if (encodeSilencePortToMotuMidiEvents(static_cast(*it), (quadlet_t *)data, offset, nevents)) { +// debugWarning("Could not encode port %s to Midi events",(*it)->getName().c_str()); +// no_problem = false; +// } + break; default: // ignore break; @@ -507,65 +464,4 @@ } return no_problem; -} - -/** - * @brief encode a packet for the packet-based ports - * - * @param data Packet data - * @param nevents number of events in data (including events of other ports & port types) - * @param dbc DataBlockCount value for this packet - * @return true if all successfull - */ -bool MotuTransmitStreamProcessor::encodePacketPorts(quadlet_t *data, unsigned int nevents, - unsigned int dbc) { - bool ok=true; - char byte; - - // Use char here since the target address won't necessarily be - // aligned; use of an unaligned quadlet_t may cause issues on - // certain architectures. Besides, the target for MIDI data going - // directly to the MOTU isn't structured in quadlets anyway; it is a - // sequence of 3 unaligned bytes. - unsigned char *target = NULL; - - for ( PortVectorIterator it = m_PacketPorts.begin(); - it != m_PacketPorts.end(); - ++it ) { - - Port *port=static_cast(*it); - assert(port); // this should not fail!! - - // Currently the only packet type of events for MOTU - // is MIDI in mbla. However in future control data - // might also be sent via "packet" events. - // assert(pinfo->getFormat()==MotuPortInfo::E_Midi); - - // FIXME: MIDI output is completely untested at present. - switch (port->getPortType()) { - case Port::E_Midi: { - MotuMidiPort *mp=static_cast(*it); - - // Send a byte if we can. MOTU MIDI data is - // sent using a 3-byte sequence starting at - // the port's position. For now we'll - // always send in the first event of a - // packet, but this might need refinement - // later. - if (mp->canRead()) { - mp->readEvent(&byte); - target = (unsigned char *)data + mp->getPosition(); - *(target++) = 0x01; - *(target++) = 0x00; - *(target++) = byte; - } - break; - } - default: - debugOutput(DEBUG_LEVEL_VERBOSE, "Unknown packet-type port type %d\n",port->getPortType()); - return ok; - } - } - - return ok; } @@ -596,7 +492,7 @@ target = (unsigned char *)data + p->getPosition(); - switch(p->getDataType()) { + switch(m_StreamProcessorManager.getAudioDataType()) { default: - case Port::E_Int24: + case StreamProcessorManager::eADT_Int24: { quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); @@ -620,5 +516,5 @@ } break; - case Port::E_Float: + case StreamProcessorManager::eADT_Float: { const float multiplier = (float)(0x7FFFFF); @@ -650,8 +546,8 @@ unsigned char *target = (unsigned char *)data + p->getPosition(); - switch (p->getDataType()) { + switch (m_StreamProcessorManager.getAudioDataType()) { default: - case Port::E_Int24: - case Port::E_Float: + case StreamProcessorManager::eADT_Int24: + case StreamProcessorManager::eADT_Float: for (j = 0; j < nevents; j++) { *target = *(target+1) = *(target+2) = 0; Index: trunk/libffado/src/libstreaming/motu/MotuReceiveStreamProcessor.cpp =================================================================== --- trunk/libffado/src/libstreaming/motu/MotuReceiveStreamProcessor.cpp (revision 750) +++ trunk/libffado/src/libstreaming/motu/MotuReceiveStreamProcessor.cpp (revision 833) @@ -187,12 +187,4 @@ if(m_data_buffer->writeFrames(n_events, (char *)(data+8), m_last_timestamp)) { - int dbc = get_bits(ntohl(quadlet[0]), 8, 8); - // process all ports that should be handled on a per-packet base - // this is MIDI for AMDTP (due to the need of DBC) - if(isRunning()) { - if (!decodePacketPorts((quadlet_t *)(data+8), n_events, dbc)) { - debugWarning("Problem decoding Packet Ports\n"); - } - } return eCRV_OK; } else { @@ -211,11 +203,10 @@ { bool no_problem=true; - for ( PortVectorIterator it = m_PeriodPorts.begin(); - it != m_PeriodPorts.end(); + for ( PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); ++it ) { if((*it)->isDisabled()) {continue;}; - //FIXME: make this into a static_cast when not DEBUG? - Port *port=dynamic_cast(*it); + Port *port=(*it); switch(port->getPortType()) { @@ -227,7 +218,10 @@ } break; - // midi is a packet based port, don't process - // case MotuPortInfo::E_Midi: - // break; + case Port::E_Midi: +// if(decodeMotuMidiEventsToPort(static_cast(*it), (quadlet_t *)data, offset, nevents)) { +// debugWarning("Could not decode packet midi data to port %s",(*it)->getName().c_str()); +// no_problem=false; +// } + break; default: // ignore @@ -236,71 +230,4 @@ } return no_problem; -} - -/** - * @brief decode a packet for the packet-based ports - * - * @param data Packet data - * @param nevents number of events in data (including events of other ports & port types) - * @param dbc DataBlockCount value for this packet - * @return true if all successfull - */ -bool MotuReceiveStreamProcessor::decodePacketPorts(quadlet_t *data, unsigned int nevents, - unsigned int dbc) { - bool ok=true; - - // Use char here since the source address won't necessarily be - // aligned; use of an unaligned quadlet_t may cause issues on - // certain architectures. Besides, the source for MIDI data going - // directly to the MOTU isn't structured in quadlets anyway; it is a - // sequence of 3 unaligned bytes. - unsigned char *src = NULL; - - for ( PortVectorIterator it = m_PacketPorts.begin(); - it != m_PacketPorts.end(); - ++it ) { - - Port *port=dynamic_cast(*it); - assert(port); // this should not fail!! - - // Currently the only packet type of events for MOTU - // is MIDI in mbla. However in future control data - // might also be sent via "packet" events, so allow - // for this possible expansion. - - // FIXME: MIDI input is completely untested at present. - switch (port->getPortType()) { - case Port::E_Midi: { - MotuMidiPort *mp=static_cast(*it); - signed int sample; - unsigned int j = 0; - // Get MIDI bytes if present anywhere in the - // packet. MOTU MIDI data is sent using a - // 3-byte sequence starting at the port's - // position. It's thought that there can never - // be more than one MIDI byte per packet, but - // for completeness we'll check the entire packet - // anyway. - src = (unsigned char *)data + mp->getPosition(); - while (j < nevents) { - if (*src==0x01 && *(src+1)==0x00) { - sample = *(src+2); - if (!mp->writeEvent(&sample)) { - debugWarning("MIDI packet port events lost\n"); - ok = false; - } - } - j++; - src += m_event_size; - } - break; - } - default: - debugOutput(DEBUG_LEVEL_VERBOSE, "Unknown packet-type port format %d\n",port->getPortType()); - return ok; - } - } - - return ok; } @@ -319,7 +246,7 @@ src_data = (unsigned char *)data + p->getPosition(); - switch(p->getDataType()) { + switch(m_StreamProcessorManager.getAudioDataType()) { default: - case Port::E_Int24: + case StreamProcessorManager::eADT_Int24: { quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); @@ -347,5 +274,5 @@ } break; - case Port::E_Float: + case StreamProcessorManager::eADT_Float: { const float multiplier = 1.0f / (float)(0x7FFFFF); Index: trunk/libffado/src/libstreaming/amdtp/AmdtpPort.h =================================================================== --- trunk/libffado/src/libstreaming/amdtp/AmdtpPort.h (revision 742) +++ trunk/libffado/src/libstreaming/amdtp/AmdtpPort.h (revision 833) @@ -47,17 +47,15 @@ public: - AmdtpAudioPort(std::string name, - enum E_Direction direction, + AmdtpAudioPort(PortManager &m, + std::string name, + enum E_Direction direction, int position, int location, enum E_Formats format) - : AudioPort(name, direction), + : AudioPort(m, name, direction), AmdtpPortInfo(position, location, format) {}; virtual ~AmdtpAudioPort() {}; - -protected: - }; @@ -74,18 +72,15 @@ public: - AmdtpMidiPort(std::string name, - enum E_Direction direction, - int position, - int location, - enum E_Formats format) - : MidiPort(name, direction), + AmdtpMidiPort(PortManager &m, + std::string name, + enum E_Direction direction, + int position, + int location, + enum E_Formats format) + : MidiPort(m, name, direction), AmdtpPortInfo(position, location, format) {}; - virtual ~AmdtpMidiPort() {}; - -protected: - }; Index: trunk/libffado/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp =================================================================== --- trunk/libffado/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp (revision 798) +++ trunk/libffado/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp (revision 833) @@ -37,4 +37,6 @@ #include +#define AMDTP_FLOAT_MULTIPLIER 2147483392.0 + namespace Streaming { @@ -45,4 +47,6 @@ , m_dimension( dimension ) , m_dbc( 0 ) + , m_nb_audio_ports( 0 ) + , m_nb_midi_ports( 0 ) {} @@ -53,8 +57,9 @@ int cycle, unsigned int dropped, unsigned int max_length ) { - struct iec61883_packet *packet = ( struct iec61883_packet * ) data; + __builtin_prefetch(data, 1, 0); // prefetch events for write, no temporal locality + struct iec61883_packet *packet = (struct iec61883_packet *)data; /* Our node ID can change after a bus reset, so it is best to fetch * our node ID for each packet. */ - packet->sid = m_1394service.getLocalNodeId() & 0x3f; + packet->sid = m_local_node_id; packet->dbs = m_dimension; @@ -249,13 +254,6 @@ int cycle, unsigned int dropped, unsigned int max_length ) { - struct iec61883_packet *packet = ( struct iec61883_packet * ) data; if ( m_data_buffer->readFrames ( m_syt_interval, ( char * ) ( data + 8 ) ) ) { - // process all ports that should be handled on a per-packet base - // this is MIDI for AMDTP (due to the need of DBC) - if ( !encodePacketPorts ( ( quadlet_t * ) ( data+8 ), m_syt_interval, packet->dbc ) ) - { - debugWarning ( "Problem encoding Packet Ports\n" ); - } debugOutput ( DEBUG_LEVEL_ULTRA_VERBOSE, "XMIT DATA (cy %04d): TSP=%011llu (%04u)\n", cycle, m_last_timestamp, ( unsigned int ) TICKS_TO_CYCLES ( m_last_timestamp ) ); @@ -278,5 +276,5 @@ /* Our node ID can change after a bus reset, so it is best to fetch * our node ID for each packet. */ - packet->sid = m_1394service.getLocalNodeId() & 0x3f; + packet->sid = m_local_node_id; packet->dbs = m_dimension; @@ -395,30 +393,9 @@ m_syt_interval ); - for ( PortVectorIterator it = m_Ports.begin(); - it != m_Ports.end(); - ++it ) - { - if ( ( *it )->getPortType() == Port::E_Midi ) - { - // we use a timing unit of 10ns - // this makes sure that for the max syt interval - // we don't have rounding, and keeps the numbers low - // we have 1 slot every 8 events - // we have syt_interval events per packet - // => syt_interval/8 slots per packet - // packet rate is 8000pkt/sec => interval=125us - // so the slot interval is (1/8000)/(syt_interval/8) - // or: 1/(1000 * syt_interval) sec - // which is 1e9/(1000*syt_interval) nsec - // or 100000/syt_interval 'units' - // the event interval is fixed to 320us = 32000 'units' - if ( ! ( *it )->useRateControl ( true, ( 100000/m_syt_interval ),32000, false ) ) - { - debugFatal ( "Could not set signal type to PeriodSignalling" ); - return false; - } - break; - } - } + if (!initPortCache()) { + debugError("Could not init port cache\n"); + return false; + } + return true; } @@ -430,57 +407,260 @@ unsigned int nevents, unsigned int offset ) { - bool no_problem = true; - - for ( PortVectorIterator it = m_PeriodPorts.begin(); - it != m_PeriodPorts.end(); - ++it ) + updatePortCache(); + switch(m_StreamProcessorManager.getAudioDataType()) { + case StreamProcessorManager::eADT_Int24: + encodeAudioPortsInt24((quadlet_t *)data, offset, nevents); + break; + case StreamProcessorManager::eADT_Float: + encodeAudioPortsFloat((quadlet_t *)data, offset, nevents); + break; + } + encodeMidiPorts((quadlet_t *)data, offset, nevents); + return true; +} + +bool +AmdtpTransmitStreamProcessor::transmitSilenceBlock( + char *data, unsigned int nevents, unsigned int offset) +{ + // no need to update the port cache when transmitting silence since + // no dynamic values are used to do so. + + encodeAudioPortsSilence((quadlet_t *)data, offset, nevents); + encodeMidiPortsSilence((quadlet_t *)data, offset, nevents); + return true; +} + +/** + * @brief encodes all audio ports in the cache to events (silent data) + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeAudioPortsSilence(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + unsigned int j; + quadlet_t *target_event; + unsigned int i; + + for (i = 0; i < m_nb_audio_ports; i++) { + target_event = (quadlet_t *)(data + i); + __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality + + for (j = 0;j < nevents; j += 1) + { + *target_event = htonl( 0x40000000 ); + target_event += m_dimension; + __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality + } + } +} + +/** + * @brief encodes all audio ports in the cache to events (float data) + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeAudioPortsFloat(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + unsigned int j; + quadlet_t *target_event; + unsigned int i; + + for (i = 0; i < m_nb_audio_ports; i++) { + struct _MBLA_port_cache &p = m_audio_ports.at(i); + target_event = (quadlet_t *)(data + i); + __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality + assert(nevents + offset <= p.buffer_size ); + + if(p.buffer && p.enabled) { + float *buffer = (float *)(p.buffer); + buffer += offset; + __builtin_prefetch(buffer, 0, 0); // prefetch events for read, no temporal locality + + for (j = 0;j < nevents; j += 1) + { + // don't care for overflow + float v = (*buffer) * AMDTP_FLOAT_MULTIPLIER; + unsigned int tmp = ((int) v); + *target_event = htonl ( ( tmp >> 8 ) | 0x40000000 ); + buffer++; + __builtin_prefetch(buffer, 0, 0); // prefetch events for read, no temporal locality + target_event += m_dimension; + __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality + } + } else { + for (j = 0;j < nevents; j += 1) + { + *target_event = htonl( 0x40000000 ); + target_event += m_dimension; + __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality + } + } + } +} + +/** + * @brief encodes all audio ports in the cache to events (int24 data) + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeAudioPortsInt24(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + unsigned int j; + quadlet_t *target_event; + unsigned int i; + + for (i = 0; i < m_nb_audio_ports; i++) { + struct _MBLA_port_cache &p = m_audio_ports.at(i); + target_event = (quadlet_t *)(data + i); + __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality + assert(nevents + offset <= p.buffer_size ); + + if(p.buffer && p.enabled) { + uint32_t *buffer = (uint32_t *)(p.buffer); + buffer += offset; + __builtin_prefetch(buffer, 0, 0); // prefetch events for read, no temporal locality + + for (j = 0; j < nevents; j += 1) + { + *target_event = htonl(((*buffer) & 0x00FFFFFF) | 0x40000000); + buffer++; + __builtin_prefetch(buffer, 0, 0); // prefetch events for read, no temporal locality + + target_event += m_dimension; + __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality + } + } else { + for (j = 0;j < nevents; j += 1) + { + *target_event = htonl( 0x40000000 ); + target_event += m_dimension; + __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality + } + } + } +} + +/** + * @brief encodes all midi ports in the cache to events (silence) + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeMidiPortsSilence(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + quadlet_t *target_event; + unsigned int i,j; + + for (i = 0; i < m_nb_midi_ports; i++) { + struct _MIDI_port_cache &p = m_midi_ports.at(i); + + for (j = p.location;j < nevents; j += 8) { + target_event = (quadlet_t *) (data + ((j * m_dimension) + p.position)); + __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality + *target_event = htonl(IEC61883_AM824_SET_LABEL(0, IEC61883_AM824_LABEL_MIDI_NO_DATA)); + } + } +} + +/** + * @brief encodes all midi ports in the cache to events + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeMidiPorts(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + quadlet_t *target_event; + unsigned int i,j; + + for (i = 0; i < m_nb_midi_ports; i++) { + struct _MIDI_port_cache &p = m_midi_ports.at(i); + if (p.buffer && p.enabled) { + uint32_t *buffer = (quadlet_t *)(p.buffer); + buffer += offset; + __builtin_prefetch(buffer, 0, 0); // prefetch events for read, no temporal locality + + for (j = p.location;j < nevents; j += 8) { + target_event = (quadlet_t *) (data + ((j * m_dimension) + p.position)); + __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality + + if ( *buffer & 0xFF000000 ) // we can send a byte + { + quadlet_t tmpval; + tmpval = ((*buffer)<<16) & 0x00FF0000; + tmpval = IEC61883_AM824_SET_LABEL(tmpval, IEC61883_AM824_LABEL_MIDI_1X); + *target_event = htonl(tmpval); + +// debugOutput ( DEBUG_LEVEL_VERBOSE, "MIDI port %s, pos=%u, loc=%u, nevents=%u, dim=%d\n", +// p.port->getName().c_str(), p.position, p.location, nevents, m_dimension ); +// debugOutput ( DEBUG_LEVEL_VERBOSE, "base=%p, target=%p, value=%08X\n", +// data, target_event, tmpval ); + } else { + // can't send a byte, either because there is no byte, + // or because this would exceed the maximum rate + // FIXME: this can be ifdef optimized since it's a constant + *target_event = htonl(IEC61883_AM824_SET_LABEL(0, IEC61883_AM824_LABEL_MIDI_NO_DATA)); + } + buffer+=8; + } + } else { + for (j = p.location;j < nevents; j += 8) { + target_event = (quadlet_t *) (data + ((j * m_dimension) + p.position)); + __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality + *target_event = htonl(IEC61883_AM824_SET_LABEL(0, IEC61883_AM824_LABEL_MIDI_NO_DATA)); + } + } + } +} + +bool +AmdtpTransmitStreamProcessor::initPortCache() { + // make use of the fact that audio ports are the first ports in + // the cluster as per AMDTP. so we can sort the ports by position + // and have very efficient lookups: + // m_float_ports.at(i).buffer -> audio stream i buffer + // for midi ports we simply cache all port info since they are (usually) not + // that numerous + m_nb_audio_ports = 0; + m_audio_ports.clear(); + + m_nb_midi_ports = 0; + m_midi_ports.clear(); + + for(PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); + ++it ) { - if ( (*it)->isDisabled() ) { continue; }; - - //FIXME: make this into a static_cast when not DEBUG? - AmdtpPortInfo *pinfo = dynamic_cast ( *it ); - assert ( pinfo ); // this should not fail!! + AmdtpPortInfo *pinfo=dynamic_cast(*it); + assert(pinfo); // this should not fail!! switch( pinfo->getFormat() ) { case AmdtpPortInfo::E_MBLA: - if( encodePortToMBLAEvents(static_cast(*it), (quadlet_t *)data, offset, nevents) ) - { - debugWarning ( "Could not encode port %s to MBLA events", (*it)->getName().c_str() ); - no_problem = false; - } + m_nb_audio_ports++; break; case AmdtpPortInfo::E_SPDIF: // still unimplemented break; - default: // ignore - break; - } - } - return no_problem; -} - -bool -AmdtpTransmitStreamProcessor::transmitSilenceBlock( - char *data, unsigned int nevents, unsigned int offset) -{ - bool no_problem = true; - for(PortVectorIterator it = m_PeriodPorts.begin(); - it != m_PeriodPorts.end(); - ++it ) - { - //FIXME: make this into a static_cast when not DEBUG? - AmdtpPortInfo *pinfo=dynamic_cast(*it); - assert(pinfo); // this should not fail!! - - switch( pinfo->getFormat() ) - { - case AmdtpPortInfo::E_MBLA: - if ( encodeSilencePortToMBLAEvents(static_cast(*it), (quadlet_t *)data, offset, nevents) ) - { - debugWarning("Could not encode port %s to MBLA events", (*it)->getName().c_str()); - no_problem = false; - } - break; - case AmdtpPortInfo::E_SPDIF: // still unimplemented + case AmdtpPortInfo::E_Midi: + m_nb_midi_ports++; break; default: // ignore @@ -488,272 +668,83 @@ } } - return no_problem; -} - -/** -* @brief decode a packet for the packet-based ports -* -* @param data Packet data -* @param nevents number of events in data (including events of other ports & port types) -* @param dbc DataBlockCount value for this packet -* @return true if all successfull -*/ -bool AmdtpTransmitStreamProcessor::encodePacketPorts ( quadlet_t *data, unsigned int nevents, unsigned int dbc ) -{ - bool ok=true; - quadlet_t byte; - - quadlet_t *target_event=NULL; - unsigned int j; - - for ( PortVectorIterator it = m_PacketPorts.begin(); - it != m_PacketPorts.end(); + + unsigned int idx; + for (idx = 0; idx < m_nb_audio_ports; idx++) { + for(PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); ++it ) + { + AmdtpPortInfo *pinfo=dynamic_cast(*it); + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "idx %u: looking at port %s at position %u\n", + idx, (*it)->getName().c_str(), pinfo->getPosition()); + if(pinfo->getPosition() == idx) { + struct _MBLA_port_cache p; + p.port = dynamic_cast(*it); + if(p.port == NULL) { + debugError("Port is not an AmdtpAudioPort!\n"); + return false; + } + p.buffer = NULL; // to be filled by updatePortCache + #ifdef DEBUG + p.buffer_size = (*it)->getBufferSize(); + #endif + + m_audio_ports.push_back(p); + debugOutput(DEBUG_LEVEL_VERBOSE, "Cached port %s at position %u\n", + p.port->getName().c_str(), idx); + goto next_index; + } + } + debugError("No MBLA port found for position %d\n", idx); + return false; +next_index: + continue; + } + + for(PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); + ++it ) { - -#ifdef DEBUG - AmdtpPortInfo *pinfo=dynamic_cast ( *it ); - assert ( pinfo ); // this should not fail!! - - // the only packet type of events for AMDTP is MIDI in mbla - assert ( pinfo->getFormat() ==AmdtpPortInfo::E_Midi ); -#endif - - AmdtpMidiPort *mp=static_cast ( *it ); - - // we encode this directly (no function call) due to the high frequency - /* idea: - spec says: current_midi_port=(dbc+j)%8; - => if we start at (dbc+stream->location-1)%8, - we'll start at the right event for the midi port. - => if we increment j with 8, we stay at the right event. - */ - // FIXME: as we know in advance how big a packet is (syt_interval) we can - // predict how much loops will be present here - // first prefill the buffer with NO_DATA's on all time muxed channels - - for ( j = ( dbc & 0x07 ) +mp->getLocation(); j < nevents; j += 8 ) - { - - quadlet_t tmpval; - - target_event= ( quadlet_t * ) ( data + ( ( j * m_dimension ) + mp->getPosition() ) ); - - if ( mp->canRead() ) // we can send a byte - { - mp->readEvent ( &byte ); - byte &= 0xFF; - tmpval=htonl ( - IEC61883_AM824_SET_LABEL ( ( byte ) <<16, - IEC61883_AM824_LABEL_MIDI_1X ) ); - - debugOutput ( DEBUG_LEVEL_ULTRA_VERBOSE, "MIDI port %s, pos=%d, loc=%d, dbc=%d, nevents=%d, dim=%d\n", - mp->getName().c_str(), mp->getPosition(), mp->getLocation(), dbc, nevents, m_dimension ); - debugOutput ( DEBUG_LEVEL_ULTRA_VERBOSE, "base=%p, target=%p, value=%08X\n", - data, target_event, tmpval ); - - } - else - { - // can't send a byte, either because there is no byte, - // or because this would exceed the maximum rate - tmpval=htonl ( - IEC61883_AM824_SET_LABEL ( 0,IEC61883_AM824_LABEL_MIDI_NO_DATA ) ); - } - - *target_event=tmpval; - } - - } - return ok; -} - -#if USE_SSE -typedef float v4sf __attribute__ ((vector_size (16))); -typedef int v4si __attribute__ ((vector_size (16))); -typedef int v2si __attribute__ ((vector_size (8))); - -int AmdtpTransmitStreamProcessor::encodePortToMBLAEvents ( AmdtpAudioPort *p, quadlet_t *data, - unsigned int offset, unsigned int nevents ) -{ - static const float sse_multiplier[4] __attribute__((aligned(16))) = { - (float)(0x7FFFFF00), - (float)(0x7FFFFF00), - (float)(0x7FFFFF00), - (float)(0x7FFFFF00) - }; - - static const int sse_mask[4] __attribute__((aligned(16))) = { - 0x40000000, 0x40000000, 0x40000000, 0x40000000 - }; - - unsigned int out[4]; - - unsigned int j=0; - unsigned int read=0; - - quadlet_t *target_event; - - target_event= ( quadlet_t * ) ( data + p->getPosition() ); - - switch ( p->getDataType() ) - { - default: - case Port::E_Int24: - { - quadlet_t *buffer= ( quadlet_t * ) ( p->getBufferAddress() ); - - assert ( nevents + offset <= p->getBufferSize() ); - - buffer+=offset; - - for ( j = 0; j < nevents; j += 1 ) // decode max nsamples - { - *target_event = htonl ( ( * ( buffer ) & 0x00FFFFFF ) | 0x40000000 ); - buffer++; - target_event += m_dimension; - } - } - break; - case Port::E_Float: - { - const float multiplier = ( float ) ( 0x7FFFFF00 ); - float *buffer= ( float * ) ( p->getBufferAddress() ); - - assert ( nevents + offset <= p->getBufferSize() ); - - buffer+=offset; - - j=0; - if(read>3) { - for (j = 0; j < read-3; j += 4) { - asm("movups %[floatbuff], %%xmm0\n\t" - "mulps %[ssemult], %%xmm0\n\t" - "cvttps2pi %%xmm0, %[out1]\n\t" - "movhlps %%xmm0, %%xmm0\n\t" - "psrld $8, %[out1]\n\t" - "cvttps2pi %%xmm0, %[out2]\n\t" - "por %[mmxmask], %[out1]\n\t" - "psrld $8, %[out2]\n\t" - "por %[mmxmask], %[out2]\n\t" - : [out1] "=&y" (*(v2si*)&out[0]), - [out2] "=&y" (*(v2si*)&out[2]) - : [floatbuff] "m" (*(v4sf*)buffer), - [ssemult] "x" (*(v4sf*)sse_multiplier), - [mmxmask] "y" (*(v2si*)sse_mask) - : "xmm0"); - buffer += 4; - *target_event = htonl(out[0]); - target_event += m_dimension; - *target_event = htonl(out[1]); - target_event += m_dimension; - *target_event = htonl(out[2]); - target_event += m_dimension; - *target_event = htonl(out[3]); - target_event += m_dimension; - } - } - for(; j < read; ++j) { - // don't care for overflow - float v = *buffer * multiplier; // v: -231 .. 231 - unsigned int tmp = (int)v; - *target_event = htonl((tmp >> 8) | 0x40000000); - - buffer++; - target_event += m_dimension; - } - - asm volatile("emms"); - break; - } - break; - } - - return 0; -} - -#else - -int AmdtpTransmitStreamProcessor::encodePortToMBLAEvents ( AmdtpAudioPort *p, quadlet_t *data, - unsigned int offset, unsigned int nevents ) -{ - unsigned int j=0; - - quadlet_t *target_event; - - target_event= ( quadlet_t * ) ( data + p->getPosition() ); - - switch ( p->getDataType() ) - { - default: - case Port::E_Int24: - { - quadlet_t *buffer= ( quadlet_t * ) ( p->getBufferAddress() ); - - assert ( nevents + offset <= p->getBufferSize() ); - - buffer+=offset; - - for ( j = 0; j < nevents; j += 1 ) // decode max nsamples - { - *target_event = htonl ( ( * ( buffer ) & 0x00FFFFFF ) | 0x40000000 ); - buffer++; - target_event += m_dimension; - } - } - break; - case Port::E_Float: - { - const float multiplier = ( float ) ( 0x7FFFFF00 ); - float *buffer= ( float * ) ( p->getBufferAddress() ); - - assert ( nevents + offset <= p->getBufferSize() ); - - buffer+=offset; - - for ( j = 0; j < nevents; j += 1 ) // decode max nsamples - { - - // don't care for overflow - float v = *buffer * multiplier; // v: -231 .. 231 - unsigned int tmp = ( ( int ) v ); - *target_event = htonl ( ( tmp >> 8 ) | 0x40000000 ); - - buffer++; - target_event += m_dimension; - } - } - break; - } - - return 0; -} -#endif - -int AmdtpTransmitStreamProcessor::encodeSilencePortToMBLAEvents ( AmdtpAudioPort *p, quadlet_t *data, - unsigned int offset, unsigned int nevents ) -{ - unsigned int j=0; - - quadlet_t *target_event; - - target_event= ( quadlet_t * ) ( data + p->getPosition() ); - - switch ( p->getDataType() ) - { - default: - case Port::E_Int24: - case Port::E_Float: - { - for ( j = 0; j < nevents; j += 1 ) // decode max nsamples - { - *target_event = htonl ( 0x40000000 ); - target_event += m_dimension; - } - } - break; - } - - return 0; + AmdtpPortInfo *pinfo=dynamic_cast(*it); + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "idx %u: looking at port %s at position %u, location %u\n", + idx, (*it)->getName().c_str(), pinfo->getPosition(), pinfo->getLocation()); + if ((*it)->getPortType() == Port::E_Midi) { + struct _MIDI_port_cache p; + p.port = dynamic_cast(*it); + if(p.port == NULL) { + debugError("Port is not an AmdtpMidiPort!\n"); + return false; + } + p.position = pinfo->getPosition(); + p.location = pinfo->getLocation(); + p.buffer = NULL; // to be filled by updatePortCache + #ifdef DEBUG + p.buffer_size = (*it)->getBufferSize(); + #endif + + m_midi_ports.push_back(p); + debugOutput(DEBUG_LEVEL_VERBOSE, "Cached port %s at position %u, location %u\n", + p.port->getName().c_str(), p.position, p.location); + } + } + + return true; +} + +void +AmdtpTransmitStreamProcessor::updatePortCache() { + unsigned int idx; + for (idx = 0; idx < m_nb_audio_ports; idx++) { + struct _MBLA_port_cache& p = m_audio_ports.at(idx); + AmdtpAudioPort *port = p.port; + p.buffer = port->getBufferAddress(); + p.enabled = !port->isDisabled(); + } + for (idx = 0; idx < m_nb_midi_ports; idx++) { + struct _MIDI_port_cache& p = m_midi_ports.at(idx); + AmdtpMidiPort *port = p.port; + p.buffer = port->getBufferAddress(); + p.enabled = !port->isDisabled(); + } } Index: trunk/libffado/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.cpp =================================================================== --- trunk/libffado/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.cpp (revision 790) +++ trunk/libffado/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.cpp (revision 833) @@ -167,11 +167,4 @@ if(m_data_buffer->writeFrames(nevents, (char *)(data+8), m_last_timestamp)) { - // process all ports that should be handled on a per-packet base - // this is MIDI for AMDTP (due to the need of DBC) - if(isRunning()) { - if (!decodePacketPorts((quadlet_t *)(data+8), nevents, packet->dbc)) { - debugWarning("Problem decoding Packet Ports\n"); - } - } return eCRV_OK; } else { @@ -193,6 +186,6 @@ bool no_problem=true; - for ( PortVectorIterator it = m_PeriodPorts.begin(); - it != m_PeriodPorts.end(); + for ( PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); ++it ) { @@ -213,7 +206,10 @@ case AmdtpPortInfo::E_SPDIF: // still unimplemented break; - /* for this processor, midi is a packet based port case AmdtpPortInfo::E_Midi: - break;*/ + if(decodeMidiEventsToPort(static_cast(*it), (quadlet_t *)data, offset, nevents)) { + debugWarning("Could not decode packet Midi to port %s",(*it)->getName().c_str()); + no_problem=false; + } + break; default: // ignore break; @@ -223,62 +219,6 @@ } -/** - * @brief decode a packet for the packet-based ports - * - * @param data Packet data - * @param nevents number of events in data (including events of other ports & port types) - * @param dbc DataBlockCount value for this packet - * @return true if all successfull - */ -bool AmdtpReceiveStreamProcessor::decodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc) -{ - bool ok=true; - - quadlet_t *target_event=NULL; - unsigned int j; - - for ( PortVectorIterator it = m_PacketPorts.begin(); - it != m_PacketPorts.end(); - ++it ) - { - -#ifdef DEBUG - AmdtpPortInfo *pinfo=dynamic_cast(*it); - assert(pinfo); // this should not fail!! - - // the only packet type of events for AMDTP is MIDI in mbla - assert(pinfo->getFormat()==AmdtpPortInfo::E_Midi); -#endif - AmdtpMidiPort *mp=static_cast(*it); - - // we decode this directly (no function call) due to the high frequency - /* idea: - spec says: current_midi_port=(dbc+j)%8; - => if we start at (dbc+stream->location-1)%8, - we'll start at the right event for the midi port. - => if we increment j with 8, we stay at the right event. - */ - // FIXME: as we know in advance how big a packet is (syt_interval) we can - // predict how much loops will be present here - for(j = (dbc & 0x07)+mp->getLocation(); j < nevents; j += 8) { - target_event=(quadlet_t *)(data + ((j * m_dimension) + mp->getPosition())); - quadlet_t sample_int=ntohl(*target_event); - // FIXME: this assumes that 2X and 3X speed isn't used, - // because only the 1X slot is put into the ringbuffer - if(IEC61883_AM824_GET_LABEL(sample_int) != IEC61883_AM824_LABEL_MIDI_NO_DATA) { - sample_int=(sample_int >> 16) & 0x000000FF; - if(!mp->writeEvent(&sample_int)) { - debugWarning("Packet port events lost\n"); - ok=false; - } - } - } - - } - - return ok; -} - #if USE_SSE +#error broken typedef float v4sf __attribute__ ((vector_size (16))); typedef int v4si __attribute__ ((vector_size (16))); @@ -306,4 +246,6 @@ switch(p->getDataType()) { default: + debugError("bad type: %d\n", p->getDataType()); + return -1; case Port::E_Int24: { @@ -374,4 +316,12 @@ } +int +AmdtpReceiveStreamProcessor::decodeMidiEventsToPort( + AmdtpMidiPort *p, quadlet_t *data, + unsigned int offset, unsigned int nevents) +{ + #warning implement +} + #else @@ -386,7 +336,9 @@ target_event=(quadlet_t *)(data + p->getPosition()); - switch(p->getDataType()) { + switch(m_StreamProcessorManager.getAudioDataType()) { default: - case Port::E_Int24: + debugError("bad type: %d\n", m_StreamProcessorManager.getAudioDataType()); + return -1; + case StreamProcessorManager::eADT_Int24: { quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); @@ -403,5 +355,5 @@ } break; - case Port::E_Float: + case StreamProcessorManager::eADT_Float: { const float multiplier = 1.0f / (float)(0x7FFFFF); @@ -429,4 +381,47 @@ return 0; } + +int +AmdtpReceiveStreamProcessor::decodeMidiEventsToPort( + AmdtpMidiPort *p, quadlet_t *data, + unsigned int offset, unsigned int nevents) +{ + unsigned int j=0; + quadlet_t *target_event; + quadlet_t sample_int; + unsigned int position = p->getPosition(); + unsigned int location = p->getLocation(); + + quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); + + assert(nevents + offset <= p->getBufferSize()); + + buffer+=offset; + + // clear + memset(buffer, 0, nevents * 4); + + // assumes that dbc%8 == 0, which is always true if data points to the + // start of a packet in blocking mode + // midi events that belong to the same time mpx-ed block should all be + // timed at the SYT timestamp of the packet. This basically means that they + // all correspond to the first audio frame in the packet. + for(j = location; j < nevents; j += 8) { + target_event=(quadlet_t *)(data + ((j * m_dimension) + position)); + sample_int=ntohl(*target_event); + // FIXME: this assumes that 2X and 3X speed isn't used, + // because only the 1X slot is put into the ringbuffer + if(IEC61883_AM824_GET_LABEL(sample_int) != IEC61883_AM824_LABEL_MIDI_NO_DATA) { + sample_int=(sample_int >> 16) & 0x000000FF; + sample_int |= 0x01000000; // flag that there is a midi event present + *buffer = sample_int; + debugOutput(DEBUG_LEVEL_VERBOSE, "Received midi byte %08X on port %p index %d\n", sample_int, p, j-location); + } + buffer += 8; // skip 8 frames + } + + return 0; +} + #endif } // end of namespace Streaming Index: trunk/libffado/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.h =================================================================== --- trunk/libffado/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.h (revision 750) +++ trunk/libffado/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.h (revision 833) @@ -115,11 +115,9 @@ unsigned int offset); - bool encodePacketPorts(quadlet_t *data, unsigned int nevents, - unsigned int dbc); - - int encodePortToMBLAEvents(AmdtpAudioPort *, quadlet_t *data, - unsigned int offset, unsigned int nevents); - int encodeSilencePortToMBLAEvents(AmdtpAudioPort *, quadlet_t *data, - unsigned int offset, unsigned int nevents); + void encodeAudioPortsSilence(quadlet_t *data, unsigned int offset, unsigned int nevents); + void encodeAudioPortsFloat(quadlet_t *data, unsigned int offset, unsigned int nevents); + void encodeAudioPortsInt24(quadlet_t *data, unsigned int offset, unsigned int nevents); + void encodeMidiPortsSilence(quadlet_t *data, unsigned int offset, unsigned int nevents); + void encodeMidiPorts(quadlet_t *data, unsigned int offset, unsigned int nevents); unsigned int getFDF(); @@ -131,4 +129,32 @@ int m_fdf; unsigned int m_dbc; + +private: // local port caching for performance + struct _MBLA_port_cache { + AmdtpAudioPort* port; + void* buffer; + bool enabled; +#ifdef DEBUG + unsigned int buffer_size; +#endif + }; + std::vector m_audio_ports; + unsigned int m_nb_audio_ports; + + struct _MIDI_port_cache { + AmdtpMidiPort* port; + void* buffer; + bool enabled; + unsigned int position; + unsigned int location; +#ifdef DEBUG + unsigned int buffer_size; +#endif + }; + std::vector m_midi_ports; + unsigned int m_nb_midi_ports; + + bool initPortCache(); + void updatePortCache(); }; Index: trunk/libffado/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.h =================================================================== --- trunk/libffado/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.h (revision 750) +++ trunk/libffado/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.h (revision 833) @@ -101,6 +101,6 @@ private: - bool decodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc); int decodeMBLAEventsToPort(AmdtpAudioPort *, quadlet_t *data, unsigned int offset, unsigned int nevents); + int decodeMidiEventsToPort(AmdtpMidiPort *p, quadlet_t *data, unsigned int offset, unsigned int nevents); unsigned int getSytInterval(); Index: trunk/libffado/src/libstreaming/amdtp/AmdtpPortInfo.h =================================================================== --- trunk/libffado/src/libstreaming/amdtp/AmdtpPortInfo.h (revision 742) +++ trunk/libffado/src/libstreaming/amdtp/AmdtpPortInfo.h (revision 833) @@ -60,11 +60,11 @@ - int getLocation() {return m_location;}; - int getPosition() {return m_position;}; + unsigned int getLocation() {return m_location;}; + unsigned int getPosition() {return m_position;}; enum E_Formats getFormat() {return m_format;}; protected: - int m_position; - int m_location; + unsigned int m_position; + unsigned int m_location; enum E_Formats m_format; Index: trunk/libffado/src/libstreaming/StreamProcessorManager.cpp =================================================================== --- trunk/libffado/src/libstreaming/StreamProcessorManager.cpp (revision 807) +++ trunk/libffado/src/libstreaming/StreamProcessorManager.cpp (revision 833) @@ -41,8 +41,9 @@ : m_is_slave( false ) , m_SyncSource(NULL) + , m_xrun_happened( false ) , m_nb_buffers( 0 ) , m_period( 0 ) + , m_audio_datatype( eADT_Float ) , m_nominal_framerate ( 0 ) - , m_xrun_happened( false ) , m_xruns(0) , m_nbperiods(0) @@ -54,9 +55,10 @@ : m_is_slave( false ) , m_SyncSource(NULL) + , m_xrun_happened( false ) , m_nb_buffers(nb_buffers) , m_period(period) + , m_audio_datatype( eADT_Float ) , m_nominal_framerate ( framerate ) , m_xruns(0) - , m_xrun_happened( false ) , m_nbperiods(0) { @@ -220,6 +222,6 @@ debugOutput( DEBUG_LEVEL_VERBOSE, "Putting StreamProcessor streams into dry-running state...\n"); debugOutput( DEBUG_LEVEL_VERBOSE, " Schedule start dry-running...\n"); - for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); - it != m_ReceiveProcessors.end(); + for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); + it != m_TransmitProcessors.end(); ++it ) { if (!(*it)->isDryRunning()) { @@ -232,6 +234,6 @@ } } - for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); - it != m_TransmitProcessors.end(); + for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); + it != m_ReceiveProcessors.end(); ++it ) { if (!(*it)->isDryRunning()) { @@ -324,5 +326,9 @@ // DLL to have a decent sync (FIXME: does the DLL get updated when dry-running)? debugOutput( DEBUG_LEVEL_VERBOSE, "Waiting for sync...\n"); - int nb_sync_runs=20; + + unsigned int nb_sync_runs = (STREAMPROCESSORMANAGER_SYNC_WAIT_TIME_MSEC * getNominalRate()); + nb_sync_runs /= 1000; + nb_sync_runs /= getPeriodSize(); + int64_t time_till_next_period; while(nb_sync_runs--) { // or while not sync-ed? @@ -417,9 +423,9 @@ } - // now align the received streams if(!alignReceivedStreams()) { - debugError("Could not align streams\n"); + debugError("Could not align streams...\n"); return false; } + debugOutput( DEBUG_LEVEL_VERBOSE, " StreamProcessor streams running...\n"); return true; @@ -429,5 +435,4 @@ StreamProcessorManager::alignReceivedStreams() { - if(m_SyncSource == NULL) return false; debugOutput( DEBUG_LEVEL_VERBOSE, "Aligning received streams...\n"); unsigned int nb_sync_runs; @@ -506,15 +511,26 @@ debugOutput( DEBUG_LEVEL_VERBOSE, "Starting Processors...\n"); - // put all SP's into dry-running state - if (!startDryRunning()) { - debugFatal("Could not put SP's in dry-running state\n"); - return false; - } - // start all SP's synchonized - if (!syncStartAll()) { + bool start_result = false; + for (int ntries; ntries < STREAMPROCESSORMANAGER_SYNCSTART_TRIES; ntries++) { + // put all SP's into dry-running state + if (!startDryRunning()) { + debugOutput(DEBUG_LEVEL_VERBOSE, "Could not put SP's in dry-running state (try %d)\n", ntries); + start_result = false; + continue; + } + + start_result = syncStartAll(); + if(start_result) { + break; + } else { + debugOutput(DEBUG_LEVEL_VERBOSE, "Sync start try %d failed...\n", ntries); + } + } + if (!start_result) { debugFatal("Could not syncStartAll...\n"); return false; } + return true; } @@ -643,17 +659,27 @@ */ - // put all SP's back into dry-running state - if (!startDryRunning()) { - debugFatal("Could not put SP's in dry-running state\n"); - return false; - } - debugOutput( DEBUG_LEVEL_VERBOSE, "Restarting StreamProcessors...\n"); // start all SP's synchonized - if (!syncStartAll()) { + bool start_result = false; + for (int ntries; ntries < STREAMPROCESSORMANAGER_SYNCSTART_TRIES; ntries++) { + // put all SP's into dry-running state + if (!startDryRunning()) { + debugShowBackLog(); + debugOutput(DEBUG_LEVEL_VERBOSE, "Could not put SP's in dry-running state (try %d)\n", ntries); + start_result = false; + continue; + } + + start_result = syncStartAll(); + if(start_result) { + break; + } else { + debugOutput(DEBUG_LEVEL_VERBOSE, "Sync start try %d failed...\n", ntries); + } + } + if (!start_result) { debugFatal("Could not syncStartAll...\n"); return false; } - debugOutput( DEBUG_LEVEL_VERBOSE, "Xrun handled...\n"); @@ -675,5 +701,5 @@ while(period_not_ready) { - debugOutput( DEBUG_LEVEL_VERBOSE, "waiting for period (%d frames in buffer)...\n", m_SyncSource->getBufferFill()); + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "waiting for period (%d frames in buffer)...\n", m_SyncSource->getBufferFill()); if(!m_SyncSource->waitForSignal()) { debugError("Error waiting for signal\n"); @@ -686,7 +712,7 @@ #ifdef DEBUG if(period_not_ready) { - debugOutput(DEBUG_LEVEL_VERBOSE, "period is not ready (bufferfill: %u)\n", bufferfill); + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "period is not ready (bufferfill: %u)\n", bufferfill); } else { - debugOutput(DEBUG_LEVEL_VERBOSE, "period is ready (bufferfill: %u)\n", bufferfill); + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "period is ready (bufferfill: %u)\n", bufferfill); } #endif @@ -717,5 +743,5 @@ // and the receive processors should have done their transfer. m_time_of_transfer = m_SyncSource->getTimeAtPeriod(); - debugOutput( DEBUG_LEVEL_VERBOSE, "transfer at %llu ticks...\n", + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "transfer at %llu ticks...\n", m_time_of_transfer); @@ -915,4 +941,5 @@ debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping StreamProcessorManager information...\n"); debugOutputShort( DEBUG_LEVEL_NORMAL, "Period count: %6d\n", m_nbperiods); + debugOutputShort( DEBUG_LEVEL_NORMAL, "Data type: %s\n", (m_audio_datatype==eADT_Float?"float":"int24")); debugOutputShort( DEBUG_LEVEL_NORMAL, " Receive processors...\n"); Index: trunk/libffado/src/libstreaming/StreamProcessorManager.h =================================================================== --- trunk/libffado/src/libstreaming/StreamProcessorManager.h (revision 750) +++ trunk/libffado/src/libstreaming/StreamProcessorManager.h (revision 833) @@ -50,4 +50,8 @@ public: + enum eADT_AudioDataType { + eADT_Int24, + eADT_Float, + }; StreamProcessorManager(); @@ -71,4 +75,9 @@ unsigned int getPeriodSize() {return m_period;}; + + bool setAudioDataType(enum eADT_AudioDataType t) + {m_audio_datatype = t; return true;}; + enum eADT_AudioDataType getAudioDataType() + {return m_audio_datatype;} void setNbBuffers(unsigned int nb_buffers) @@ -139,4 +148,5 @@ unsigned int m_nb_buffers; unsigned int m_period; + enum eADT_AudioDataType m_audio_datatype; unsigned int m_nominal_framerate; unsigned int m_xruns; Index: trunk/libffado/src/libstreaming/generic/PortManager.cpp =================================================================== --- trunk/libffado/src/libstreaming/generic/PortManager.cpp (revision 750) +++ trunk/libffado/src/libstreaming/generic/PortManager.cpp (revision 833) @@ -36,28 +36,18 @@ PortManager::PortManager() { - } PortManager::~PortManager() { -// deleteAllPorts(); -} - -// bool PortManager::setPortBuffersize(unsigned int newsize) { -// debugOutput( DEBUG_LEVEL_VERBOSE, "setting port buffer size to %d\n",newsize); -// -// -// for ( PortVectorIterator it = m_Ports.begin(); -// it != m_Ports.end(); -// ++it ) -// { -// if(!(*it)->setBufferSize(newsize)) { -// debugFatal("Could not set buffer size for port %s\n",(*it)->getName().c_str()); -// return false; -// } -// } -// -// return true; //not found -// -// } + flushDebugOutput(); + // delete all ports that are still registered to the manager + for ( PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); + ++it ) + { + debugOutput( DEBUG_LEVEL_VERBOSE, "deleting port %s at %p\n", (*it)->getName().c_str(), *it); + flushDebugOutput(); + delete *it; //FIXME + } +} bool PortManager::makeNameUnique(Port *port) @@ -96,10 +86,10 @@ * @return */ -bool PortManager::addPort(Port *port) +bool PortManager::registerPort(Port *port) { assert(port); - debugOutput( DEBUG_LEVEL_VERBOSE, "Adding port %s, type: %d, dir: %d, dtype: %d\n", - port->getName().c_str(), port->getPortType(), port->getDirection(), port->getDataType()); + debugOutput( DEBUG_LEVEL_VERBOSE, "Adding port %s, type: %d, dir: %d\n", + port->getName().c_str(), port->getPortType(), port->getDirection()); port->setVerboseLevel(getDebugLevel()); @@ -113,8 +103,8 @@ } -bool PortManager::deletePort(Port *port) +bool PortManager::unregisterPort(Port *port) { assert(port); - debugOutput( DEBUG_LEVEL_VERBOSE, "deleting port %s\n",port->getName().c_str()); + debugOutput( DEBUG_LEVEL_VERBOSE, "unregistering port %s\n",port->getName().c_str()); for ( PortVectorIterator it = m_Ports.begin(); @@ -124,5 +114,4 @@ if(*it == port) { m_Ports.erase(it); -// delete *it; return true; } @@ -132,20 +121,4 @@ return false; //not found - -} - -void PortManager::deleteAllPorts() -{ - debugOutput( DEBUG_LEVEL_VERBOSE, "deleting all ports\n"); - - for ( PortVectorIterator it = m_Ports.begin(); - it != m_Ports.end(); - ++it ) - { - m_Ports.erase(it); -// delete *it; - } - - return; } @@ -213,5 +186,5 @@ { if(!(*it)->init()) { - debugFatal("Could not init port %s",(*it)->getName().c_str()); + debugFatal("Could not init port %s\n", (*it)->getName().c_str()); return false; } @@ -222,8 +195,4 @@ bool PortManager::preparePorts() { debugOutput( DEBUG_LEVEL_VERBOSE, "preparing ports\n"); - - // clear the cache lists - m_PeriodPorts.clear(); - m_PacketPorts.clear(); for ( PortVectorIterator it = m_Ports.begin(); @@ -236,17 +205,4 @@ } - // now prepare the cache lists - switch((*it)->getSignalType()) { - case Port::E_PacketSignalled: - m_PacketPorts.push_back(*it); - break; - case Port::E_PeriodSignalled: - m_PeriodPorts.push_back(*it); - break; - default: - debugWarning("%s has unsupported port type\n", - (*it)->getName().c_str()); - break; - } } return true; Index: trunk/libffado/src/libstreaming/generic/StreamProcessor.h =================================================================== --- trunk/libffado/src/libstreaming/generic/StreamProcessor.h (revision 807) +++ trunk/libffado/src/libstreaming/generic/StreamProcessor.h (revision 833) @@ -137,4 +137,5 @@ IsoHandlerManager& m_IsoHandlerManager; StreamProcessorManager& m_StreamProcessorManager; + unsigned int m_local_node_id; public: // the public receive/transmit functions @@ -292,5 +293,5 @@ {debugWarning("call not allowed\n"); return false;}; protected: // some generic helpers - int provideSilenceToPort(AudioPort *p, unsigned int offset, unsigned int nevents); + int provideSilenceToPort(Port *p, unsigned int offset, unsigned int nevents); bool provideSilenceBlock(unsigned int nevents, unsigned int offset); @@ -325,5 +326,6 @@ uint64_t m_last_timestamp; /// last timestamp (in ticks) uint64_t m_last_timestamp2; /// last timestamp (in ticks) - uint64_t m_last_timestamp_at_period_ticks; + bool m_correct_last_timestamp; + uint64_t m_last_timestamp_at_period_ticks; // FIXME: still used? //--- data buffering and accounting Index: trunk/libffado/src/libstreaming/generic/Port.cpp =================================================================== --- trunk/libffado/src/libstreaming/generic/Port.cpp (revision 750) +++ trunk/libffado/src/libstreaming/generic/Port.cpp (revision 833) @@ -23,4 +23,5 @@ #include "Port.h" +#include "PortManager.h" #include @@ -31,26 +32,21 @@ IMPL_DEBUG_MODULE( Port, Port, DEBUG_LEVEL_NORMAL ); -Port::Port(std::string name, enum E_PortType porttype, enum E_Direction direction) - : m_Name(name), - m_SignalType(E_PeriodSignalled), - m_BufferType(E_PointerBuffer), - m_disabled(true), - m_buffersize(0), - m_eventsize(0), - m_DataType(E_Int24), - m_PortType(porttype), - m_Direction(direction), - m_buffer(0), - m_ringbuffer(0), - m_use_external_buffer(false), - m_do_ratecontrol(false), - m_event_interval(0), - m_slot_interval(0), - m_rate_counter(0), - m_rate_counter_minimum(0), - m_average_ratecontrol(false), - m_State(E_Created) +Port::Port(PortManager& m, std::string name, + enum E_PortType porttype, enum E_Direction direction) + : m_Name( name ) + , m_disabled( true ) + , m_buffersize( 0 ) + , m_PortType( porttype ) + , m_Direction( direction ) + , m_buffer( NULL ) + , m_manager( m ) + , m_State( E_Created ) { + m_manager.registerPort(this); +} +Port::~Port() { + debugOutput( DEBUG_LEVEL_VERBOSE, "deleting port %s\n", getName().c_str()); + m_manager.unregisterPort(this); } @@ -69,36 +65,9 @@ } - if (m_buffersize==0) { + if (m_buffersize == 0) { debugFatal("Cannot initialize a port with buffersize=0\n"); return false; } - switch (m_BufferType) { - case E_PointerBuffer: - if (m_use_external_buffer) { - // don't do anything - } else if (!allocateInternalBuffer()) { - debugFatal("Could not allocate internal buffer!\n"); - return false; - } - break; - - case E_RingBuffer: - if (m_use_external_buffer) { - debugFatal("Cannot use an external ringbuffer! \n"); - return false; - } else if (!allocateInternalRingBuffer()) { - debugFatal("Could not allocate internal ringbuffer!\n"); - return false; - } - break; - default: - debugFatal("Unsupported buffer type! (%d)\n",(int)m_BufferType); - return false; - break; - } - - m_eventsize=getEventSize(); // this won't change, so cache it - m_State = E_Initialized; return true; @@ -106,9 +75,6 @@ bool Port::reset() { - if (m_BufferType==E_RingBuffer) { - ffado_ringbuffer_reset(m_ringbuffer); - } return true; -}; +} bool Port::setName(std::string name) { @@ -134,131 +100,14 @@ unsigned int Port::getEventSize() { - switch (m_DataType) { - case E_Float: - return sizeof(float); - case E_Int24: // 24 bit 2's complement, packed in a 32bit integer (LSB's) - return sizeof(uint32_t); - case E_MidiEvent: - return sizeof(uint32_t); - default: - return 0; - } -} - -bool Port::setDataType(enum E_DataType d) { - debugOutput( DEBUG_LEVEL_VERBOSE, "Setting datatype to %d for port %s\n",(int) d,m_Name.c_str()); - if (m_State != E_Created) { - debugFatal("Port (%s) not in E_Created state: %d\n",m_Name.c_str(),m_State); - return false; - } - - // do some sanity checks - bool type_is_ok=false; - switch (m_PortType) { - case E_Audio: - if(d == E_Int24) type_is_ok=true; - if(d == E_Float) type_is_ok=true; - break; - case E_Midi: - if(d == E_MidiEvent) type_is_ok=true; - break; - case E_Control: - if(d == E_Default) type_is_ok=true; - break; - default: - break; - } - - if(!type_is_ok) { - debugFatal("Datatype not supported by this type of port!\n"); - return false; - } - - m_DataType=d; - return true; -} - -bool Port::setSignalType(enum E_SignalType s) { - debugOutput( DEBUG_LEVEL_VERBOSE, "Setting signaltype to %d for port %s\n",(int)s,m_Name.c_str()); - if (m_State != E_Created) { - debugFatal("Port (%s) not in E_Created state: %d\n",m_Name.c_str(),m_State); - return false; - } - - // do some sanity checks - bool type_is_ok=false; - switch (m_PortType) { - case E_Audio: - if(s == E_PeriodSignalled) type_is_ok=true; - break; - case E_Midi: - if(s == E_PacketSignalled) type_is_ok=true; - break; - case E_Control: - if(s == E_PeriodSignalled) type_is_ok=true; - break; - default: - break; - } - if(!type_is_ok) { - debugFatal("Signalling type not supported by this type of port!\n"); - return false; - } - m_SignalType=s; - return true; -} - -bool Port::setBufferType(enum E_BufferType b) { - debugOutput( DEBUG_LEVEL_VERBOSE, "Setting buffer type to %d for port %s\n",(int)b,m_Name.c_str()); - if (m_State != E_Created) { - debugFatal("Port (%s) not in E_Created state: %d\n",m_Name.c_str(),m_State); - return false; - } - // do some sanity checks - bool type_is_ok=false; - switch (m_PortType) { - case E_Audio: - if(b == E_PointerBuffer) type_is_ok=true; - break; - case E_Midi: - if(b == E_RingBuffer) type_is_ok=true; - break; - case E_Control: - break; - default: - break; - } - if(!type_is_ok) { - debugFatal("Buffer type not supported by this type of port!\n"); - return false; - } - m_BufferType=b; - return true; -} - -bool Port::useExternalBuffer(bool b) { - // If called on an initialised stream but the request isn't for a change silently - // allow it (relied on by C API as used by jack backend driver) - if (m_State==E_Initialized && m_use_external_buffer==b) - return true; - - debugOutput( DEBUG_LEVEL_VERBOSE, "Setting external buffer use to %d for port %s\n",(int)b,m_Name.c_str()); - - if (m_State != E_Created) { - debugFatal("Port (%s) not in E_Created state: %d\n",m_Name.c_str(),m_State); - return false; - } - m_use_external_buffer=b; - return true; + return 4; // whether it's float, int24, midi or control, it's 4 } // buffer handling api's for pointer buffers /** - * Get the buffer address (being the external or the internal one). + * Get the buffer address * * @param buff */ void *Port::getBufferAddress() { - assert(m_BufferType==E_PointerBuffer); return m_buffer; }; @@ -266,213 +115,9 @@ /** * Set the external buffer address. - * only call this when you have specified that you will use - * an external buffer before doing the init() * * @param buff */ -void Port::setExternalBufferAddress(void *buff) { - assert(m_BufferType==E_PointerBuffer); - assert(m_use_external_buffer); // don't call this with an internal buffer! +void Port::setBufferAddress(void *buff) { m_buffer=buff; -}; - -// buffer handling api's for ringbuffers -bool Port::writeEvent(void *event) { - -#ifdef DEBUG - if (m_State != E_Initialized) { - debugFatal("Port (%s) not in E_Initialized state: %d\n",m_Name.c_str(),m_State); - return false; - } - - if(m_BufferType!=E_RingBuffer) { - debugError("operation not allowed on non E_RingBuffer ports\n"); - show(); - return false; - } - assert(m_ringbuffer); -#endif - - debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Writing event %08X with size %d to port %s\n",*((quadlet_t *)event),m_eventsize, m_Name.c_str()); - - return (ffado_ringbuffer_write(m_ringbuffer, (char *)event, m_eventsize)==m_eventsize); -} - -bool Port::readEvent(void *event) { - -#ifdef DEBUG - if (m_State != E_Initialized) { - debugFatal("Port (%s) not in E_Initialized state: %d\n",m_Name.c_str(),m_State); - return false; - } - - if(m_BufferType!=E_RingBuffer) { - debugError("operation not allowed on non E_RingBuffer ports\n"); - show(); - return false; - } - assert(m_ringbuffer); -#endif - - - unsigned int read=ffado_ringbuffer_read(m_ringbuffer, (char *)event, m_eventsize); - - debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Reading event %X with size %d from port %s\n",*((quadlet_t *)event),m_eventsize,m_Name.c_str()); - - - return (read==m_eventsize); -} - -int Port::writeEvents(void *event, unsigned int nevents) { - -#ifdef DEBUG - if (m_State != E_Initialized) { - debugFatal("Port (%s) not in E_Initialized state: %d\n",m_Name.c_str(),m_State); - return false; - } - - if(m_BufferType!=E_RingBuffer) { - debugError("operation not allowed on non E_RingBuffer ports\n"); - show(); - return false; - } - assert(m_ringbuffer); -#endif - - - unsigned int bytes2write=m_eventsize*nevents; - - unsigned int written=ffado_ringbuffer_write(m_ringbuffer, (char *)event,bytes2write)/m_eventsize; - -#ifdef DEBUG - if(written) { - unsigned int i=0; - quadlet_t * tmp=(quadlet_t *)event; - debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Written %d events (",written); - for (i=0;i= m_eventsize); - - if(byte_present_in_buffer) { - - if(!m_do_ratecontrol) { - return true; - } - - if(m_rate_counter <= 0) { - // update the counter - if(m_average_ratecontrol) { - m_rate_counter += m_event_interval; - assert(m_rate_counterevent_interval) { - debugWarning("Rate control not needed!\n",m_Name.c_str()); - m_do_ratecontrol=false; - return false; - } - if(slot_interval==0) { - debugFatal("Cannot have slot interval == 0!\n"); - m_do_ratecontrol=false; - return false; - } - if(event_interval==0) { - debugFatal("Cannot have event interval == 0!\n"); - m_do_ratecontrol=false; - return false; - } - m_do_ratecontrol=use; - m_event_interval=event_interval; - m_slot_interval=slot_interval; - m_rate_counter=0; - - // NOTE: pretty arbitrary, but in average mode this limits the peak stream rate - m_rate_counter_minimum=-(2*event_interval); - - m_average_ratecontrol=average; - - } else { - debugOutput(DEBUG_LEVEL_VERBOSE, "Disabling rate control for port %s...\n",m_Name.c_str()); - m_do_ratecontrol=use; - } - return true; } @@ -482,5 +127,5 @@ debugOutput(DEBUG_LEVEL_VERBOSE, "Enabling port %s...\n",m_Name.c_str()); m_disabled=false; -}; +} /// Disable the port. (this can be called anytime) @@ -489,85 +134,14 @@ debugOutput(DEBUG_LEVEL_VERBOSE, "Disabling port %s...\n",m_Name.c_str()); m_disabled=false; -}; - - -/* Private functions */ - -bool Port::allocateInternalBuffer() { - int event_size=getEventSize(); - - debugOutput(DEBUG_LEVEL_VERBOSE, - "Allocating internal buffer of %d events with size %d (%s)\n", - m_buffersize, event_size, m_Name.c_str()); - - if(m_buffer) { - debugWarning("already has an internal buffer attached, re-allocating\n"); - freeInternalBuffer(); - } - - m_buffer=calloc(m_buffersize,event_size); - if (!m_buffer) { - debugFatal("could not allocate internal buffer\n"); - m_buffersize=0; - return false; - } - - return true; -} - -void Port::freeInternalBuffer() { - debugOutput(DEBUG_LEVEL_VERBOSE, - "Freeing internal buffer (%s)\n",m_Name.c_str()); - - if(m_buffer) { - free(m_buffer); - m_buffer=0; - } -} - -bool Port::allocateInternalRingBuffer() { - int event_size=getEventSize(); - - debugOutput(DEBUG_LEVEL_VERBOSE, - "Allocating internal buffer of %d events with size %d (%s)\n", - m_buffersize, event_size, m_Name.c_str()); - - if(m_ringbuffer) { - debugWarning("already has an internal ringbuffer attached, re-allocating\n"); - freeInternalRingBuffer(); - } - - m_ringbuffer=ffado_ringbuffer_create(m_buffersize * event_size); - if (!m_ringbuffer) { - debugFatal("could not allocate internal ringbuffer\n"); - m_buffersize=0; - return false; - } - - return true; -} - -void Port::freeInternalRingBuffer() { - debugOutput(DEBUG_LEVEL_VERBOSE, - "Freeing internal ringbuffer (%s)\n",m_Name.c_str()); - - if(m_ringbuffer) { - ffado_ringbuffer_free(m_ringbuffer); - m_ringbuffer=0; - } } void Port::show() { debugOutput(DEBUG_LEVEL_VERBOSE,"Name : %s\n", m_Name.c_str()); - debugOutput(DEBUG_LEVEL_VERBOSE,"Signal Type : %d\n", m_SignalType); - debugOutput(DEBUG_LEVEL_VERBOSE,"Buffer Type : %d\n", m_BufferType); debugOutput(DEBUG_LEVEL_VERBOSE,"Enabled? : %d\n", m_disabled); debugOutput(DEBUG_LEVEL_VERBOSE,"State? : %d\n", m_State); debugOutput(DEBUG_LEVEL_VERBOSE,"Buffer Size : %d\n", m_buffersize); - debugOutput(DEBUG_LEVEL_VERBOSE,"Event Size : %d\n", m_eventsize); - debugOutput(DEBUG_LEVEL_VERBOSE,"Data Type : %d\n", m_DataType); + debugOutput(DEBUG_LEVEL_VERBOSE,"Event Size : %d\n", getEventSize()); debugOutput(DEBUG_LEVEL_VERBOSE,"Port Type : %d\n", m_PortType); debugOutput(DEBUG_LEVEL_VERBOSE,"Direction : %d\n", m_Direction); - debugOutput(DEBUG_LEVEL_VERBOSE,"Rate Control? : %d\n", m_do_ratecontrol); } Index: trunk/libffado/src/libstreaming/generic/PortManager.h =================================================================== --- trunk/libffado/src/libstreaming/generic/PortManager.h (revision 742) +++ trunk/libffado/src/libstreaming/generic/PortManager.h (revision 833) @@ -33,5 +33,4 @@ namespace Streaming { -class Port; typedef std::vector PortVector; typedef std::vector::iterator PortVectorIterator; @@ -50,12 +49,9 @@ virtual bool makeNameUnique(Port *port); - virtual bool addPort(Port *port); - virtual bool deletePort(Port *port); - virtual void deleteAllPorts(); + virtual bool registerPort(Port *port); + virtual bool unregisterPort(Port *port); int getPortCount(enum Port::E_PortType); int getPortCount(); - -// virtual bool setPortBuffersize(unsigned int newsize); Port *getPortAtIdx(unsigned int index); @@ -69,10 +65,6 @@ protected: PortVector m_Ports; - PortVector m_PacketPorts; - PortVector m_PeriodPorts; -// PortVector m_SamplePorts; DECLARE_DEBUG_MODULE; - }; Index: trunk/libffado/src/libstreaming/generic/Port.h =================================================================== --- trunk/libffado/src/libstreaming/generic/Port.h (revision 742) +++ trunk/libffado/src/libstreaming/generic/Port.h (revision 833) @@ -33,4 +33,5 @@ namespace Streaming { +class PortManager; /*! @@ -53,46 +54,8 @@ OK. - \todo rework the implementation into something more beautifull */ class Port { public: - friend class PortManager; - - /* - * IMPORTANT: if you add something to any of these enum's, be sure to - * check the code where they are used. - */ - - /*! - \brief Specifies the buffer type for ports - - A PointerBuffer uses the getBufferAddress() and setBufferAddres() interface - A Ringbuffer uses the read/write interface - */ - enum E_BufferType { - E_PointerBuffer, - E_RingBuffer - }; - - /*! - \brief Specifies the signalling type for ports - */ - enum E_SignalType { - E_PacketSignalled, ///< the port is to be processed for every packet - E_PeriodSignalled, ///< the port is to be processed after a period of frames -// E_SampleSignalled ///< the port is to be processed after each frame (sample) - }; - - /*! - \brief The datatype of the port buffer - */ - enum E_DataType { - E_Float, - E_Int24, - E_MidiEvent, - E_Default, - }; - /*! \brief The port type @@ -112,8 +75,7 @@ }; - Port(std::string name, enum E_PortType porttype, enum E_Direction direction); - - virtual ~Port() - {}; + Port(PortManager&, std::string name, enum E_PortType, enum E_Direction); + + virtual ~Port(); @@ -142,31 +104,4 @@ unsigned int getEventSize(); - /** - * \brief sets the event type for the port buffer - * - * \note use before calling init() - */ - virtual bool setDataType(enum E_DataType); - - enum E_DataType getDataType() {return m_DataType;}; - - /** - * \brief sets the event type for the port buffer - * - * \note use before calling init() - */ - virtual bool setSignalType(enum E_SignalType ); - - enum E_SignalType getSignalType() {return m_SignalType;}; ///< returns the signalling type of the port - - /** - * \brief sets the buffer type for the port - * - * \note use before calling init() - */ - virtual bool setBufferType(enum E_BufferType ); - - enum E_BufferType getBufferType() {return m_BufferType;}; ///< returns the buffer type of the port - enum E_PortType getPortType() {return m_PortType;}; ///< returns the port type (is fixed) enum E_Direction getDirection() {return m_Direction;}; ///< returns the direction (is fixed) @@ -193,130 +128,38 @@ virtual bool setBufferSize(unsigned int); - /** - * \brief use an external buffer (or not) - * - * \note use before calling init() - */ - virtual bool useExternalBuffer(bool b); - - void setExternalBufferAddress(void *buff); - - - /** - * \brief enable/disable ratecontrol - * - * Rate control is nescessary for some types of ports (most notably - * midi). The StreamProcessor that handles the port should call canRead() - * everytime a 'slot' that could be filled with an event passes. The canRead - * function will return true if - * (1) there is an event ready in the buffer - * (2) we are allowed to send an event in this slot - * - * Setting the rate works is done with the slot_interval and the event_interval - * parameters. On every call to canRead(), a counter is decremented with - * slot_interval. If the counter drops below 0, canRead() returns true and resets - * the counter to event_interval. - * - * e.g. for AMDTP midi, we are only allowed to send a midi byte every 320us - * if the SYT interval is 8, there is exactly one midi slot every packet. - * therefore the slot_interval is 1/8000s (=125us), and the event_interval - * is 320us. - * - * Note that the interval parameters are unitless, so you can adapt them - * to your needs. In the AMDTP case for example, when the SYT interval is 32 - * (when the samplerate is 192kHz for example) there are 4 midi slots in - * each packet, making the slot time interval 125us/4 = 31.25us. - * The event time interval stays the same (320us). We can however set the - * slot_interval to 3125 and the event_interval to 32000, as we can choose - * the unit of the counter time step (chosen to be 10ns in this case). - * - * The average argument deserves some attention too. If average is true, we use - * average rate control. This means that on average there will be a delay of - * event_interval between two events, but that sometimes there can be a smaller - * delay. This mode fixes the average rate of the stream. - * If average is false, there will always be a minimal delay of event_interval - * between two events. This means that the maximum rate of the stream is fixed, - * and that the average rate will be lower than (or at max equal to) the rate in - * average mode. - * - * - * \note only works for the E_RingBuffer ports - * \note use before calling init() - * - * @param use set this to true to use rate control - * @param slot_interval the interval between slots - * @param event_interval the interval between events - * @param average use average rate control - * @return true if rate control was enabled/disabled successfully - */ - virtual bool useRateControl(bool use, unsigned int slot_interval, - unsigned int event_interval, bool average); - - bool usingRateControl() { return m_do_ratecontrol;}; ///< are we using rate control? - - /** - * Can we send an event in this slot. subject to rate control and - * byte availability. - * @return true if we can send an event on this slot - */ - bool canRead(); - - // FIXME: this is not really OO, but for performance??? + void setBufferAddress(void *buff); void *getBufferAddress(); - // TODO: extend this with a blocking interface - bool writeEvent(void *event); ///< write one event - bool readEvent(void *event); ///< read one event - int writeEvents(void *event, unsigned int nevents); ///< write multiple events - int readEvents(void *event, unsigned int nevents); ///< read multiple events + PortManager& getManager() { return m_manager; }; virtual void setVerboseLevel(int l); virtual void show(); - + protected: std::string m_Name; ///< Port name, [at construction] - - enum E_SignalType m_SignalType; ///< Signalling type, [at construction] - enum E_BufferType m_BufferType; ///< Buffer type, [at construction] - bool m_disabled; ///< is the port disabled?, [anytime] unsigned int m_buffersize; - unsigned int m_eventsize; - - enum E_DataType m_DataType; + enum E_PortType m_PortType; enum E_Direction m_Direction; void *m_buffer; - ffado_ringbuffer_t *m_ringbuffer; - bool m_use_external_buffer; - - bool m_do_ratecontrol; - int m_event_interval; - int m_slot_interval; - int m_rate_counter; - int m_rate_counter_minimum; - bool m_average_ratecontrol; - - bool allocateInternalBuffer(); - void freeInternalBuffer(); - - bool allocateInternalRingBuffer(); - void freeInternalRingBuffer(); + + PortManager& m_manager; DECLARE_DEBUG_MODULE; - - // the state machine - protected: - enum EStates { - E_Created, - E_Initialized, - E_Prepared, - E_Running, - E_Error - }; - - enum EStates m_State; + +// the state machine +protected: + enum EStates { + E_Created, + E_Initialized, + E_Prepared, + E_Running, + E_Error + }; + + enum EStates m_State; }; @@ -330,13 +173,9 @@ public: - AudioPort(std::string name, enum E_Direction direction) - : Port(name, E_Audio, direction) + AudioPort(PortManager& m, std::string name, enum E_Direction direction) + : Port(m, name, E_Audio, direction) {}; virtual ~AudioPort() {}; - -protected: - - }; @@ -350,13 +189,8 @@ public: - MidiPort(std::string name, enum E_Direction direction) - : Port(name, E_Midi, direction) + MidiPort(PortManager& m, std::string name, enum E_Direction direction) + : Port(m, name, E_Midi, direction) {}; virtual ~MidiPort() {}; - - -protected: - - }; @@ -370,13 +204,8 @@ public: - ControlPort(std::string name, enum E_Direction direction) - : Port(name, E_Control, direction) + ControlPort(PortManager& m, std::string name, enum E_Direction direction) + : Port(m, name, E_Control, direction) {}; virtual ~ControlPort() {}; - - -protected: - - }; Index: trunk/libffado/src/libstreaming/generic/StreamProcessor.cpp =================================================================== --- trunk/libffado/src/libstreaming/generic/StreamProcessor.cpp (revision 807) +++ trunk/libffado/src/libstreaming/generic/StreamProcessor.cpp (revision 833) @@ -66,8 +66,10 @@ , m_IsoHandlerManager( parent.get1394Service().getIsoHandlerManager() ) // local cache , m_StreamProcessorManager( m_Parent.getDeviceManager().getStreamProcessorManager() ) // local cache + , m_local_node_id ( 0 ) // local cache , m_channel( -1 ) - , m_dropped(0) - , m_last_timestamp(0) - , m_last_timestamp2(0) + , m_dropped( 0 ) + , m_last_timestamp( 0 ) + , m_last_timestamp2( 0 ) + , m_correct_last_timestamp( false ) , m_scratch_buffer( NULL ) , m_scratch_buffer_size_bytes( 0 ) @@ -88,8 +90,10 @@ debugOutput(DEBUG_LEVEL_VERBOSE,"Could not unregister stream processor with the Iso manager\n"); } + // make the threads leave the wait condition + POST_SEMAPHORE; + sem_destroy(&m_signal_semaphore); if (m_data_buffer) delete m_data_buffer; if (m_scratch_buffer) delete[] m_scratch_buffer; - sem_destroy(&m_signal_semaphore); } @@ -130,5 +134,5 @@ // the waitForClient in IsoHandler will take care of the fact that the frames are // not present in time - unsigned int packets_to_prebuffer = (getPacketsPerPeriod() * (m_StreamProcessorManager.getNbBuffers())); + unsigned int packets_to_prebuffer = (getPacketsPerPeriod() * (m_StreamProcessorManager.getNbBuffers())) + 10; debugOutput(DEBUG_LEVEL_VERBOSE, "Nominal prebuffer: %u\n", packets_to_prebuffer); return packets_to_prebuffer; @@ -286,7 +290,9 @@ unsigned char channel, unsigned char tag, unsigned char sy, unsigned int cycle, unsigned int dropped) { +#ifdef DEBUG if(m_last_cycle == -1) { debugOutput(DEBUG_LEVEL_VERBOSE, "Handler for %s SP %p is alive (cycle = %u)\n", getTypeString(), this, cycle); } +#endif int dropped_cycles = 0; @@ -301,10 +307,5 @@ this, dropped_cycles, cycle, dropped, cycle, m_last_cycle); m_dropped += dropped_cycles; - m_in_xrun = true; m_last_cycle = cycle; - POST_SEMAPHORE; - return RAW1394_ISO_DEFER; - //flushDebugOutput(); - //assert(0); } } @@ -344,4 +345,5 @@ // the received data can be discarded while waiting for the stream // to be disabled + // similarly for dropped packets return RAW1394_ISO_OK; } @@ -366,4 +368,24 @@ // check the packet header enum eChildReturnValue result = processPacketHeader(data, length, channel, tag, sy, cycle, dropped_cycles); + + // handle dropped cycles + if(dropped_cycles) { + // make sure the last_timestamp is corrected + m_correct_last_timestamp = true; + if (m_state == ePS_Running) { + // this is an xrun situation + m_in_xrun = true; + debugWarning("Should update state to WaitingForStreamDisable due to dropped packet xrun\n"); + m_cycle_to_switch_state = cycle + 1; // switch in the next cycle + m_next_state = ePS_WaitingForStreamDisable; + // execute the requested change + if (!updateState()) { // we are allowed to change the state directly + debugError("Could not update state!\n"); + POST_SEMAPHORE; + return RAW1394_ISO_ERROR; + } + } + } + if (result == eCRV_OK) { debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "RECV: CY=%04u TS=%011llu\n", @@ -372,4 +394,12 @@ m_last_good_cycle = cycle; m_last_dropped = dropped_cycles; + + if(m_correct_last_timestamp) { + // they represent a discontinuity in the timestamps, and hence are + // to be dealt with + debugWarning("(%p) Correcting timestamp for dropped cycles, discarding packet...\n", this); + m_data_buffer->setBufferTailTimestamp(substractTicks(m_last_timestamp, getNominalFramesPerPacket() * getTicksPerFrame())); + m_correct_last_timestamp = false; + } // check whether we are waiting for a stream to startup @@ -406,27 +436,4 @@ POST_SEMAPHORE; return RAW1394_ISO_ERROR; - } - } - - // handle dropped cycles - if(dropped_cycles) { - // they represent a discontinuity in the timestamps, and hence are - // to be dealt with - debugWarning("(%p) Correcting timestamp for dropped cycles, discarding packet...\n", this); - m_data_buffer->setBufferTailTimestamp(m_last_timestamp); - if (m_state == ePS_Running) { - // this is an xrun situation - m_in_xrun = true; - debugWarning("Should update state to WaitingForStreamDisable due to dropped packet xrun\n"); - m_cycle_to_switch_state = cycle + 1; // switch in the next cycle - m_next_state = ePS_WaitingForStreamDisable; - // execute the requested change - if (!updateState()) { // we are allowed to change the state directly - debugError("Could not update state!\n"); - POST_SEMAPHORE; - return RAW1394_ISO_ERROR; - } - POST_SEMAPHORE; - return RAW1394_ISO_DEFER; } } @@ -466,5 +473,5 @@ unsigned int signal_period = m_signal_period * (semval + 1) + m_signal_offset; if(bufferfill >= signal_period) { - debugOutput(DEBUG_LEVEL_VERBOSE, "(%p) buffer fill (%d) > signal period (%d), sem_val=%d\n", + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "(%p) buffer fill (%d) > signal period (%d), sem_val=%d\n", this, m_data_buffer->getBufferFill(), signal_period, semval); POST_SEMAPHORE; @@ -472,4 +479,5 @@ // the process thread should have higher prio such that we are blocked until // the samples are processed. + return RAW1394_ISO_DEFER; } } @@ -508,7 +516,9 @@ int cycle_diff; +#ifdef DEBUG if(m_last_cycle == -1) { debugOutput(DEBUG_LEVEL_VERBOSE, "Handler for %s SP %p is alive (cycle = %d)\n", getTypeString(), this, cycle); } +#endif int dropped_cycles = 0; @@ -529,4 +539,5 @@ debugWarning("dropped packets xrun\n"); debugOutput(DEBUG_LEVEL_VERBOSE, "Should update state to WaitingForStreamDisable due to dropped packets xrun\n"); + m_cycle_to_switch_state = cycle + 1; m_next_state = ePS_WaitingForStreamDisable; // execute the requested change @@ -543,4 +554,5 @@ } +#ifdef DEBUG // bypass based upon state if (m_state == ePS_Invalid) { @@ -548,4 +560,6 @@ return RAW1394_ISO_ERROR; } +#endif + if (m_state == ePS_Created) { *tag = 0; @@ -577,4 +591,5 @@ m_in_xrun = true; debugOutput(DEBUG_LEVEL_VERBOSE, "Should update state to WaitingForStreamDisable due to data xrun\n"); + m_cycle_to_switch_state = cycle + 1; m_next_state = ePS_WaitingForStreamDisable; // execute the requested change @@ -670,5 +685,5 @@ m_in_xrun = true; debugOutput(DEBUG_LEVEL_VERBOSE, "Should update state to WaitingForStreamDisable due to data xrun\n"); - m_cycle_to_switch_state = cycle+1; // switch in the next cycle + m_cycle_to_switch_state = cycle + 1; // switch in the next cycle m_next_state = ePS_WaitingForStreamDisable; // execute the requested change @@ -689,4 +704,5 @@ m_in_xrun = true; debugOutput(DEBUG_LEVEL_VERBOSE, "Should update state to WaitingForStreamDisable due to header xrun\n"); + m_cycle_to_switch_state = cycle + 1; // switch in the next cycle m_next_state = ePS_WaitingForStreamDisable; // execute the requested change @@ -837,9 +853,9 @@ unsigned int bufferfill = m_data_buffer->getBufferFill(); if (bufferfill >= m_signal_period + m_signal_offset) { - debugOutput(DEBUG_LEVEL_VERBOSE, "(%p) sufficient frames in buffer (%d / %d), posting semaphore\n", + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "(%p) sufficient frames in buffer (%d / %d), posting semaphore\n", this, bufferfill, m_signal_period + m_signal_offset); POST_SEMAPHORE; } else { - debugOutput(DEBUG_LEVEL_VERBOSE, "(%p) insufficient frames in buffer (%d / %d), not posting semaphore\n", + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "(%p) insufficient frames in buffer (%d / %d), not posting semaphore\n", this, bufferfill, m_signal_period + m_signal_offset); } @@ -894,15 +910,17 @@ StreamProcessor::waitForSignal() { + debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) wait ...\n", this, getTypeString()); int result; - if(m_state == ePS_Running) { + if(m_state == ePS_Running && m_next_state == ePS_Running) { result = sem_wait(&m_signal_semaphore); #ifdef DEBUG int tmp; sem_getvalue(&m_signal_semaphore, &tmp); - debugOutput(DEBUG_LEVEL_VERBOSE, " sem_wait returns: %d, sem_value: %d\n", result, tmp); + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " sem_wait returns: %d, sem_value: %d\n", result, tmp); #endif return result == 0; } else { // when we're not running, we can always provide frames + // when we're in a state transition, keep iterating too debugOutput(DEBUG_LEVEL_VERBOSE, "Not running...\n"); return true; @@ -925,7 +943,7 @@ StreamProcessor::canProcessPackets() { - if(m_state != ePS_Running) return true; + if(m_state != ePS_Running || m_next_state != ePS_Running) return true; bool result; - int bufferfill; + unsigned int bufferfill; if(getType() == ePT_Receive) { bufferfill = m_data_buffer->getBufferSpace(); @@ -934,6 +952,6 @@ } result = bufferfill > getNominalFramesPerPacket(); - debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) for a bufferfill of %d, we return %d\n", - this, ePTToString(getType()), bufferfill, result); +// debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) for a bufferfill of %d, we return %d\n", +// this, ePTToString(getType()), bufferfill, result); return result; } @@ -960,26 +978,12 @@ { bool no_problem=true; - for ( PortVectorIterator it = m_PeriodPorts.begin(); - it != m_PeriodPorts.end(); + for ( PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); ++it ) { if((*it)->isDisabled()) {continue;}; - //FIXME: make this into a static_cast when not DEBUG? - Port *port=dynamic_cast(*it); - - switch(port->getPortType()) { - - case Port::E_Audio: - if(provideSilenceToPort(static_cast(*it), offset, nevents)) { - debugWarning("Could not put silence into to port %s",(*it)->getName().c_str()); - no_problem=false; - } - break; - // midi is a packet based port, don't process - // case MotuPortInfo::E_Midi: - // break; - - default: // ignore - break; + if(provideSilenceToPort((*it), offset, nevents)) { + debugWarning("Could not put silence into to port %s",(*it)->getName().c_str()); + no_problem=false; } } @@ -988,11 +992,13 @@ int -StreamProcessor::provideSilenceToPort( - AudioPort *p, unsigned int offset, unsigned int nevents) +StreamProcessor::provideSilenceToPort(Port *p, unsigned int offset, unsigned int nevents) { unsigned int j=0; - switch(p->getDataType()) { + switch(p->getPortType()) { default: - case Port::E_Int24: + debugError("Invalid port type: %d\n", p->getPortType()); + return -1; + case Port::E_Midi: + case Port::E_Control: { quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); @@ -1000,5 +1006,5 @@ buffer+=offset; - for(j = 0; j < nevents; j += 1) { // decode max nsamples + for(j = 0; j < nevents; j += 1) { *(buffer)=0; buffer++; @@ -1006,14 +1012,30 @@ } break; - case Port::E_Float: - { - float *buffer=(float *)(p->getBufferAddress()); - assert(nevents + offset <= p->getBufferSize()); - buffer+=offset; - - for(j = 0; j < nevents; j += 1) { // decode max nsamples - *buffer = 0.0; - buffer++; + case Port::E_Audio: + switch(m_StreamProcessorManager.getAudioDataType()) { + case StreamProcessorManager::eADT_Int24: + { + quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); + assert(nevents + offset <= p->getBufferSize()); + buffer+=offset; + + for(j = 0; j < nevents; j += 1) { + *(buffer)=0; + buffer++; + } } + break; + case StreamProcessorManager::eADT_Float: + { + float *buffer=(float *)(p->getBufferAddress()); + assert(nevents + offset <= p->getBufferSize()); + buffer+=offset; + + for(j = 0; j < nevents; j += 1) { + *buffer = 0.0; + buffer++; + } + } + break; } break; @@ -1063,4 +1085,25 @@ } + // set the parameters of ports we can: + // we want the audio ports to be period buffered, + // and the midi ports to be packet buffered + for ( PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); + ++it ) + { + debugOutput(DEBUG_LEVEL_VERBOSE, "Setting up port %s\n",(*it)->getName().c_str()); + if(!(*it)->setBufferSize(m_StreamProcessorManager.getPeriodSize())) { + debugFatal("Could not set buffer size to %d\n",m_StreamProcessorManager.getPeriodSize()); + return false; + } + } + // the API specific settings of the ports should already be set, + // as this is called from the processorManager->prepare() + // so we can init the ports + if(!PortManager::initPorts()) { + debugFatal("Could not initialize ports\n"); + return false; + } + if (!prepareChild()) { debugFatal("Could not prepare child\n"); @@ -1089,4 +1132,5 @@ m_cycle_to_switch_state = TICKS_TO_CYCLES(time_instant); m_next_state = state; + POST_SEMAPHORE; // needed to ensure that things don't get deadlocked return true; } @@ -1286,10 +1330,11 @@ case ePS_Created: assert(m_data_buffer); - // object just created - result = m_data_buffer->init(); // prepare the framerate estimate ticks_per_frame = (TICKS_PER_SECOND*1.0) / ((float)m_StreamProcessorManager.getNominalRate()); m_ticks_per_frame = ticks_per_frame; + m_local_node_id= m_1394service.getLocalNodeId() & 0x3f; + m_correct_last_timestamp = false; + debugOutput(DEBUG_LEVEL_VERBOSE,"Initializing remote ticks/frame to %f\n", ticks_per_frame); @@ -1307,65 +1352,4 @@ result &= m_data_buffer->setWrapValue(128L*TICKS_PER_SECOND); result &= m_data_buffer->prepare(); // FIXME: the name - - // set the parameters of ports we can: - // we want the audio ports to be period buffered, - // and the midi ports to be packet buffered - for ( PortVectorIterator it = m_Ports.begin(); - it != m_Ports.end(); - ++it ) - { - debugOutput(DEBUG_LEVEL_VERBOSE, "Setting up port %s\n",(*it)->getName().c_str()); - if(!(*it)->setBufferSize(m_StreamProcessorManager.getPeriodSize())) { - debugFatal("Could not set buffer size to %d\n",m_StreamProcessorManager.getPeriodSize()); - return false; - } - switch ((*it)->getPortType()) { - case Port::E_Audio: - if(!(*it)->setSignalType(Port::E_PeriodSignalled)) { - debugFatal("Could not set signal type to PeriodSignalling"); - return false; - } - // buffertype and datatype are dependant on the API - debugWarning("---------------- ! Doing hardcoded dummy setup ! --------------\n"); - // buffertype and datatype are dependant on the API - if(!(*it)->setBufferType(Port::E_PointerBuffer)) { - debugFatal("Could not set buffer type"); - return false; - } - if(!(*it)->useExternalBuffer(true)) { - debugFatal("Could not set external buffer usage"); - return false; - } - if(!(*it)->setDataType(Port::E_Float)) { - debugFatal("Could not set data type"); - return false; - } - break; - case Port::E_Midi: - if(!(*it)->setSignalType(Port::E_PacketSignalled)) { - debugFatal("Could not set signal type to PacketSignalling"); - return false; - } - // buffertype and datatype are dependant on the API - debugWarning("---------------- ! Doing hardcoded test setup ! --------------\n"); - // buffertype and datatype are dependant on the API - if(!(*it)->setBufferType(Port::E_RingBuffer)) { - debugFatal("Could not set buffer type"); - return false; - } - if(!(*it)->setDataType(Port::E_MidiEvent)) { - debugFatal("Could not set data type"); - return false; - } - break; - default: - debugWarning("Unsupported port type specified\n"); - break; - } - } - // the API specific settings of the ports should already be set, - // as this is called from the processorManager->prepare() - // so we can init the ports - result &= PortManager::initPorts(); break; @@ -1449,4 +1433,5 @@ // a running stream has been detected debugOutput(DEBUG_LEVEL_VERBOSE, "StreamProcessor %p started dry-running at cycle %d\n", this, m_last_cycle); + m_local_node_id = m_1394service.getLocalNodeId() & 0x3f; if (getType() == ePT_Receive) { // this to ensure that there is no discontinuity when starting to @@ -1555,4 +1540,5 @@ this, m_last_cycle); m_in_xrun = false; + m_local_node_id = m_1394service.getLocalNodeId() & 0x3f; m_data_buffer->setTransparent(false); break; @@ -1632,5 +1618,5 @@ // do init here result = doStop(); - if (result) return true; + if (result) {POST_SEMAPHORE; return true;} else goto updateState_exit_change_failed; } @@ -1642,5 +1628,5 @@ } result = doWaitForRunningStream(); - if (result) return true; + if (result) {POST_SEMAPHORE; return true;} else goto updateState_exit_change_failed; } @@ -1653,5 +1639,5 @@ } result = doDryRunning(); - if (result) return true; + if (result) {POST_SEMAPHORE; return true;} else goto updateState_exit_change_failed; } @@ -1670,5 +1656,5 @@ result = doWaitForStreamEnable(); } - if (result) return true; + if (result) {POST_SEMAPHORE; return true;} else goto updateState_exit_change_failed; } @@ -1687,5 +1673,5 @@ result = doRunning(); } - if (result) return true; + if (result) {POST_SEMAPHORE; return true;} else goto updateState_exit_change_failed; } @@ -1697,5 +1683,5 @@ } result = doWaitForStreamDisable(); - if (result) return true; + if (result) {POST_SEMAPHORE; return true;} else goto updateState_exit_change_failed; } @@ -1707,5 +1693,5 @@ } result = doDryRunning(); - if (result) return true; + if (result) {POST_SEMAPHORE; return true;} else goto updateState_exit_change_failed; } @@ -1715,8 +1701,10 @@ debugError("Invalid state transition: %s => %s\n", ePSToString(m_state), ePSToString(next_state)); + POST_SEMAPHORE; return false; updateState_exit_change_failed: debugError("State transition failed: %s => %s\n", ePSToString(m_state), ePSToString(next_state)); + POST_SEMAPHORE; return false; } Index: trunk/libffado/src/motu/motu_avdevice.cpp =================================================================== --- trunk/libffado/src/motu/motu_avdevice.cpp (revision 785) +++ trunk/libffado/src/motu/motu_avdevice.cpp (revision 833) @@ -554,16 +554,8 @@ // event data. asprintf(&buff,"%s_cap_MIDI0",id.c_str()); - p = new Streaming::MotuMidiPort(buff, + p = new Streaming::MotuMidiPort(*m_receiveProcessor, buff, Streaming::Port::E_Capture, 4); if (!p) { debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n", buff); - } else { - if (!m_receiveProcessor->addPort(p)) { - debugWarning("Could not register port with stream processor\n"); - free(buff); - return false; - } else { - debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n", buff); - } } free(buff); @@ -613,16 +605,8 @@ // of the event data. asprintf(&buff,"%s_pbk_MIDI0",id.c_str()); - p = new Streaming::MotuMidiPort(buff, + p = new Streaming::MotuMidiPort(*m_transmitProcessor, buff, Streaming::Port::E_Capture, 4); if (!p) { debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n", buff); - } else { - if (!m_receiveProcessor->addPort(p)) { - debugWarning("Could not register port with stream processor\n"); - free(buff); - return false; - } else { - debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n", buff); - } } free(buff); @@ -862,17 +846,8 @@ Streaming::Port *p=NULL; - p = new Streaming::MotuAudioPort(name, direction, position, size); + p = new Streaming::MotuAudioPort(*s_processor, name, direction, position, size); if (!p) { debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",name); - } else { - if (!s_processor->addPort(p)) { - debugWarning("Could not register port with stream processor\n"); - free(name); - return false; - } else { - debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",name); - } - p->enable(); } free(name); Index: trunk/libffado/src/ffado.cpp =================================================================== --- trunk/libffado/src/ffado.cpp (revision 807) +++ trunk/libffado/src/ffado.cpp (revision 833) @@ -184,5 +184,5 @@ if(!dev->m_deviceManager->prepareStreaming()) { debugFatal("Could not prepare the streaming system\n"); - return 0; + return -1; } return 0; @@ -226,5 +226,6 @@ } -int ffado_streaming_wait(ffado_device_t *dev) { +ffado_wait_response +ffado_streaming_wait(ffado_device_t *dev) { static int periods=0; static int periods_print=0; @@ -242,10 +243,16 @@ } - if(dev->m_deviceManager->waitForPeriod()) { - return dev->options.period_size; + enum DeviceManager::eWaitResult result; + result = dev->m_deviceManager->waitForPeriod(); + if(result == DeviceManager::eWR_OK) { + return ffado_wait_ok; + } else if (result == DeviceManager::eWR_Xrun) { + debugWarning("Handled XRUN\n"); + xruns++; + return ffado_wait_xrun; } else { - debugWarning("XRUN\n"); + debugError("Unhandled XRUN (BUG)\n"); xruns++; - return -1; + return ffado_wait_error; } } @@ -261,23 +268,4 @@ int ffado_streaming_transfer_buffers(ffado_device_t *dev) { return dev->m_deviceManager->getStreamProcessorManager().transfer(); -} - - -int ffado_streaming_write(ffado_device_t *dev, int i, ffado_sample_t *buffer, int nsamples) { - Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Playback); - // use an assert here performancewise, - // it should already have failed before, if not correct - assert(p); - - return p->writeEvents((void *)buffer, nsamples); -} - -int ffado_streaming_read(ffado_device_t *dev, int i, ffado_sample_t *buffer, int nsamples) { - Streaming::Port *p=dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Capture); - // use an assert here performancewise, - // it should already have failed before, if not correct - assert(p); - - return p->readEvents((void *)buffer, nsamples); } @@ -354,59 +342,39 @@ } -int ffado_streaming_set_stream_buffer_type(ffado_device_t *dev, int i, - ffado_streaming_buffer_type t, enum Streaming::Port::E_Direction direction) { - - Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, direction); - if(!p) { - debugWarning("Could not get %s port at index %d\n", - (direction==Streaming::Port::E_Playback?"Playback":"Capture"),i); - return -1; - } - +int ffado_streaming_set_audio_datatype(ffado_device_t *dev, + ffado_streaming_audio_datatype t) { switch(t) { - case ffado_buffer_type_int24: - if (!p->setDataType(Streaming::Port::E_Int24)) { - debugWarning("%s: Could not set data type to Int24\n",p->getName().c_str()); + case ffado_audio_datatype_int24: + if(!dev->m_deviceManager->getStreamProcessorManager().setAudioDataType( + Streaming::StreamProcessorManager::eADT_Int24)) { + debugError("Could not set datatype\n"); + return -1; + } + break; + case ffado_audio_datatype_float: + if(!dev->m_deviceManager->getStreamProcessorManager().setAudioDataType( + Streaming::StreamProcessorManager::eADT_Float)) { + debugError("Could not set datatype\n"); + return -1; + } + break; + default: + debugError("Invalid audio datatype\n"); return -1; - } - if (!p->setBufferType(Streaming::Port::E_PointerBuffer)) { - debugWarning("%s: Could not set buffer type to Pointerbuffer\n",p->getName().c_str()); - return -1; - } - break; - case ffado_buffer_type_float: - if (!p->setDataType(Streaming::Port::E_Float)) { - debugWarning("%s: Could not set data type to Float\n",p->getName().c_str()); - return -1; - } - if (!p->setBufferType(Streaming::Port::E_PointerBuffer)) { - debugWarning("%s: Could not set buffer type to Pointerbuffer\n",p->getName().c_str()); - return -1; - } - break; - case ffado_buffer_type_midi: - if (!p->setDataType(Streaming::Port::E_MidiEvent)) { - debugWarning("%s: Could not set data type to MidiEvent\n",p->getName().c_str()); - return -1; - } - if (!p->setBufferType(Streaming::Port::E_RingBuffer)) { - debugWarning("%s: Could not set buffer type to Ringbuffer\n",p->getName().c_str()); - return -1; - } - break; - default: - debugWarning("%s: Unsupported buffer type\n",p->getName().c_str()); - return -1; - } - return 0; - -} - -int ffado_streaming_set_playback_buffer_type(ffado_device_t *dev, int i, ffado_streaming_buffer_type t) { - return ffado_streaming_set_stream_buffer_type(dev, i, t, Streaming::Port::E_Playback); -} - -int ffado_streaming_set_capture_buffer_type(ffado_device_t *dev, int i, ffado_streaming_buffer_type t) { - return ffado_streaming_set_stream_buffer_type(dev, i, t, Streaming::Port::E_Capture); + } + return 0; +} + +ffado_streaming_audio_datatype ffado_streaming_get_audio_datatype(ffado_device_t *dev) { + switch(dev->m_deviceManager->getStreamProcessorManager().getAudioDataType()) { + case Streaming::StreamProcessorManager::eADT_Int24: + return ffado_audio_datatype_int24; + case Streaming::StreamProcessorManager::eADT_Float: + return ffado_audio_datatype_float; + default: + debugError("Invalid audio datatype\n"); + return ffado_audio_datatype_error; + } + #warning FIXME } @@ -435,28 +403,19 @@ } -// TODO: the way port buffers are set in the C api doesn't satisfy me int ffado_streaming_set_capture_stream_buffer(ffado_device_t *dev, int i, char *buff) { - Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Capture); - - // use an assert here performancewise, - // it should already have failed before, if not correct - assert(p); - - p->useExternalBuffer(true); - p->setExternalBufferAddress((void *)buff); - - return 0; - + Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Capture); + // use an assert here performancewise, + // it should already have failed before, if not correct + assert(p); + p->setBufferAddress((void *)buff); + return 0; } int ffado_streaming_set_playback_stream_buffer(ffado_device_t *dev, int i, char *buff) { - Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Playback); - // use an assert here performancewise, - // it should already have failed before, if not correct - assert(p); - - p->useExternalBuffer(true); - p->setExternalBufferAddress((void *)buff); - - return 0; -} + Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Playback); + // use an assert here performancewise, + // it should already have failed before, if not correct + assert(p); + p->setBufferAddress((void *)buff); + return 0; +} Index: trunk/libffado/src/dice/dice_avdevice.cpp =================================================================== --- trunk/libffado/src/dice/dice_avdevice.cpp (revision 785) +++ trunk/libffado/src/dice/dice_avdevice.cpp (revision 833) @@ -839,4 +839,5 @@ case ePT_Analog: p=new Streaming::AmdtpAudioPort( + *processor, portname.str(), direction, @@ -849,4 +850,5 @@ case ePT_MIDI: p=new Streaming::AmdtpMidiPort( + *processor, portname.str(), direction, @@ -864,10 +866,4 @@ if (!p) { debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",channelInfo->name.c_str()); - } else { - - if (!processor->addPort(p)) { - debugWarning("Could not register port with stream processor\n"); - return false; - } } Index: trunk/libffado/src/libutil/TimestampedBuffer.cpp =================================================================== --- trunk/libffado/src/libutil/TimestampedBuffer.cpp (revision 807) +++ trunk/libffado/src/libutil/TimestampedBuffer.cpp (revision 833) @@ -38,4 +38,5 @@ #define DLL_COEFF_C (DLL_OMEGA * DLL_OMEGA) +#define FRAMES_PER_PROCESS_BLOCK 8 /* #define ENTER_CRITICAL_SECTION { \ @@ -58,5 +59,6 @@ TimestampedBuffer::TimestampedBuffer(TimestampedBufferClient *c) - : m_event_buffer(NULL), m_cluster_buffer(NULL), + : m_event_buffer(NULL), m_process_buffer(NULL), m_cluster_size( 0 ), + m_process_block_size( 0 ), m_event_size(0), m_events_per_frame(0), m_buffer_size(0), m_bytes_per_frame(0), m_bytes_per_buffer(0), @@ -75,5 +77,5 @@ TimestampedBuffer::~TimestampedBuffer() { ffado_ringbuffer_free(m_event_buffer); - free(m_cluster_buffer); + free(m_process_buffer); } @@ -278,16 +280,4 @@ /** - * \brief Initializes the TimestampedBuffer - * - * Initializes the TimestampedBuffer, should be called before anything else - * is done. - * - * @return true if successful - */ -bool TimestampedBuffer::init() { - return true; -} - -/** * \brief Resets the TimestampedBuffer * @@ -346,5 +336,10 @@ // allocate the temporary cluster buffer - if( !(m_cluster_buffer=(char *)calloc(m_events_per_frame,m_event_size))) { + // NOTE: has to be a multiple of 8 in order to + // correctly decode midi bytes (since that + // enforces packet alignment) + m_cluster_size = m_events_per_frame * m_event_size; + m_process_block_size = m_cluster_size * FRAMES_PER_PROCESS_BLOCK; + if( !(m_process_buffer=(char *)calloc(m_process_block_size, 1))) { debugFatal("Could not allocate temporary cluster buffer\n"); ffado_ringbuffer_free(m_event_buffer); @@ -535,11 +530,11 @@ debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Transferring period...\n"); int xrun; - unsigned int offset=0; + unsigned int offset = 0; ffado_ringbuffer_data_t vec[2]; // we received one period of frames // this is period_size*dimension of events - unsigned int events2write=nbframes*m_events_per_frame; - unsigned int bytes2write=events2write*m_event_size; + unsigned int events2write = nbframes * m_events_per_frame; + unsigned int bytes2write = events2write * m_event_size; /* write events2write bytes to the ringbuffer @@ -551,15 +546,14 @@ * Make sure that we cannot end up on a non-cluster aligned position! */ - unsigned int cluster_size=m_events_per_frame*m_event_size; - - while(bytes2write>0) { - int byteswritten=0; - - unsigned int frameswritten=(nbframes*cluster_size-bytes2write)/cluster_size; - offset=frameswritten; + + while(bytes2write > 0) { + int byteswritten = 0; + + unsigned int frameswritten = (nbframes * m_cluster_size - bytes2write) / m_cluster_size; + offset = frameswritten; ffado_ringbuffer_get_write_vector(m_event_buffer, vec); - if(vec[0].len==0) { // this indicates a full event buffer + if(vec[0].len + vec[1].len < m_process_block_size) { // this indicates a full event buffer debugError("Event buffer overrun in buffer %p, fill: %u, bytes2write: %u \n", this, ffado_ringbuffer_read_space(m_event_buffer), bytes2write); @@ -574,10 +568,12 @@ * this can happen because the ringbuffer size is always a power of 2 */ - if(vec[0].lenprocessWriteBlock(m_cluster_buffer, 1, offset); - - if(xrun<0) { + // note that we always process 8 frames at once, in order to ensure that + // we don't have to care about the DBC field + xrun = m_Client->processWriteBlock(m_process_buffer, FRAMES_PER_PROCESS_BLOCK, offset); + + if(xrun < 0) { // xrun detected debugError("Frame buffer underrun in buffer %p\n",this); @@ -588,25 +584,25 @@ // the write function handles the wrap around. ffado_ringbuffer_write(m_event_buffer, - m_cluster_buffer, - cluster_size); + m_process_buffer, + m_process_block_size); // we advanced one cluster_size - bytes2write-=cluster_size; + bytes2write -= m_process_block_size; } else { // - if(bytes2write>vec[0].len) { + if(bytes2write > vec[0].len) { // align to a cluster boundary - byteswritten=vec[0].len-(vec[0].len%cluster_size); + byteswritten = vec[0].len - (vec[0].len % m_process_block_size); } else { - byteswritten=bytes2write; + byteswritten = bytes2write; } xrun = m_Client->processWriteBlock(vec[0].buf, - byteswritten/cluster_size, - offset); - - if(xrun<0) { - // xrun detected + byteswritten / m_cluster_size, + offset); + + if(xrun < 0 ) { + // xrun detected debugError("Frame buffer underrun in buffer %p\n",this); return false; // FIXME: return false ? @@ -617,6 +613,6 @@ } - // the bytes2write should always be cluster aligned - assert(bytes2write%cluster_size==0); + // the bytes2write should always be process block aligned + assert(bytes2write % m_process_block_size == 0); } @@ -644,5 +640,5 @@ int xrun; - unsigned int offset=0; + unsigned int offset = 0; ffado_ringbuffer_data_t vec[2]; @@ -650,6 +646,6 @@ // this is period_size*dimension of events - unsigned int events2read=nbframes*m_events_per_frame; - unsigned int bytes2read=events2read*m_event_size; + unsigned int events2read = nbframes * m_events_per_frame; + unsigned int bytes2read = events2read * m_event_size; /* read events2read bytes from the ringbuffer * first see if it can be done in one read. @@ -660,15 +656,14 @@ * Make sure that we cannot end up on a non-cluster aligned position! */ - unsigned int cluster_size=m_events_per_frame*m_event_size; - - while(bytes2read>0) { - unsigned int framesread=(nbframes*cluster_size-bytes2read)/cluster_size; - offset=framesread; - - int bytesread=0; + + while(bytes2read > 0) { + unsigned int framesread = (nbframes * m_cluster_size - bytes2read) / m_cluster_size; + offset = framesread; + + int bytesread = 0; ffado_ringbuffer_get_read_vector(m_event_buffer, vec); - if(vec[0].len==0) { // this indicates an empty event buffer + if(vec[0].len + vec[1].len < m_process_block_size) { // this indicates an empty event buffer debugError("Event buffer underrun in buffer %p\n",this); return false; @@ -680,13 +675,15 @@ * this can happen because the ringbuffer size is always a power of 2 */ - if(vec[0].lenprocessReadBlock(m_cluster_buffer, 1, offset); - - if(xrun<0) { + // note that we always process 8 frames at once, in order to ensure that + // we don't have to care about the DBC field + xrun = m_Client->processReadBlock(m_process_buffer, FRAMES_PER_PROCESS_BLOCK, offset); + + if(xrun < 0) { // xrun detected debugError("Frame buffer overrun in buffer %p\n",this); @@ -695,19 +692,19 @@ // we advanced one cluster_size - bytes2read-=cluster_size; + bytes2read -= m_process_block_size; } else { // - if(bytes2read>vec[0].len) { + if(bytes2read > vec[0].len) { // align to a cluster boundary - bytesread=vec[0].len-(vec[0].len%cluster_size); + bytesread = vec[0].len - (vec[0].len % m_process_block_size); } else { - bytesread=bytes2read; + bytesread = bytes2read; } assert(m_Client); - xrun = m_Client->processReadBlock(vec[0].buf, bytesread/cluster_size, offset); - - if(xrun<0) { + xrun = m_Client->processReadBlock(vec[0].buf, bytesread/m_cluster_size, offset); + + if(xrun < 0) { // xrun detected debugError("Frame buffer overrun in buffer %p\n",this); @@ -720,5 +717,5 @@ // the bytes2read should always be cluster aligned - assert(bytes2read%cluster_size==0); + assert(bytes2read % m_process_block_size == 0); } @@ -1177,9 +1174,9 @@ if (diff > max_abs_diff) { - debugShowBackLogLines(100); +// debugShowBackLogLines(100); debugWarning("(%p) difference rather large (+): diff="TIMESTAMP_FORMAT_SPEC", max="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n", this, diff, max_abs_diff, ts, pred_buffer_next_tail_timestamp); } else if (diff < -max_abs_diff) { - debugShowBackLogLines(100); +// debugShowBackLogLines(100); debugWarning("(%p) difference rather large (-): diff="TIMESTAMP_FORMAT_SPEC", max="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n", this, diff, -max_abs_diff, ts, pred_buffer_next_tail_timestamp); Index: trunk/libffado/src/libutil/TimestampedBuffer.h =================================================================== --- trunk/libffado/src/libutil/TimestampedBuffer.h (revision 807) +++ trunk/libffado/src/libutil/TimestampedBuffer.h (revision 833) @@ -89,38 +89,4 @@ virtual ~TimestampedBuffer(); - /** - * @brief waits for the availability of frames (blocking) - * @param nframes number of frames - * - * @return true if frames are available, false if not (e.g. signal occurred) - */ - bool waitForFrames(unsigned int nframes); - - /** - * @brief waits for the availability of frames (blocking) - * - * waits for one update period of frames - * - * @return true if frames are available, false if not (e.g. signal occurred) - */ - bool waitForFrames(); - - /** - * @brief waits for the availability of frames (non-blocking) - * @param nframes number of frames - * - * @return true if frames are available, false if not - */ - bool tryWaitForFrames(unsigned int nframes); - - /** - * @brief waits for the availability of frames (non-blocking) - * - * waits for one update period of frames - * - * @return true if frames are available, false if not - */ - bool tryWaitForFrames(); - bool writeDummyFrame(); bool dropFrames ( unsigned int nbframes ); @@ -134,5 +100,4 @@ bool blockProcessReadFrames ( unsigned int nbframes ); - bool init(); bool prepare(); bool clearBuffer(); @@ -201,5 +166,7 @@ ffado_ringbuffer_t * m_event_buffer; - char* m_cluster_buffer; + char* m_process_buffer; + unsigned int m_cluster_size; + unsigned int m_process_block_size; unsigned int m_event_size; // the size of one event Index: trunk/libffado/src/genericavc/avc_avdevice.cpp =================================================================== --- trunk/libffado/src/genericavc/avc_avdevice.cpp (revision 784) +++ trunk/libffado/src/genericavc/avc_avdevice.cpp (revision 833) @@ -443,5 +443,5 @@ } - if (!addPlugToProcessor(*outputPlug,p, + if (!addPlugToProcessor(*outputPlug, p, Streaming::Port::E_Capture)) { debugFatal("Could not add plug to processor!\n"); @@ -472,5 +472,5 @@ if (snoopMode) { - if (!addPlugToProcessor(*inputPlug,p, + if (!addPlugToProcessor(*inputPlug, p, Streaming::Port::E_Capture)) { debugFatal("Could not add plug to processor!\n"); @@ -478,5 +478,5 @@ } } else { - if (!addPlugToProcessor(*inputPlug,p, + if (!addPlugToProcessor(*inputPlug, p, Streaming::Port::E_Playback)) { debugFatal("Could not add plug to processor!\n"); @@ -532,4 +532,5 @@ channelInfo->m_name.c_str(), channelInfo->m_streamPosition, channelInfo->m_location); p=new Streaming::AmdtpAudioPort( + *processor, portname.str(), direction, @@ -544,4 +545,5 @@ channelInfo->m_name.c_str(), channelInfo->m_streamPosition, processor->getPortCount(Streaming::Port::E_Midi)); p=new Streaming::AmdtpMidiPort( + *processor, portname.str(), direction, @@ -565,4 +567,5 @@ channelInfo->m_name.c_str(), channelInfo->m_streamPosition, channelInfo->m_location); p=new Streaming::AmdtpAudioPort( + *processor, portname.str(), direction, @@ -581,10 +584,4 @@ 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; - } } } Index: trunk/libffado/src/bebob/focusrite/focusrite_saffirepro.cpp =================================================================== --- trunk/libffado/src/bebob/focusrite/focusrite_saffirepro.cpp (revision 783) +++ trunk/libffado/src/bebob/focusrite/focusrite_saffirepro.cpp (revision 833) @@ -231,4 +231,12 @@ "UseHighVoltageRail", "Use High Supply", "Prefer the high voltage power supply rail")); + result &= m_ControlContainer->addElement( + new SaffireProMultiControl(*this, SaffireProMultiControl::eTCT_ExitStandalone, + "ExitStandalone", "Exit Standalone mode", "Try to leave standalonbe mode")); + + result &= m_ControlContainer->addElement( + new SaffireProMultiControl(*this, SaffireProMultiControl::eTCT_PllLockRange, + "PllLockRange", "PLL Lock Range", "Get/Set PLL Lock range")); + if (!result) { debugWarning("One or more device control elements could not be created."); @@ -484,4 +492,13 @@ void +SaffireProDevice::exitStandalone() { + debugOutput( DEBUG_LEVEL_VERBOSE, "exit standalone mode...\n" ); + if ( !setSpecificValue(FR_SAFFIREPRO_CMD_ID_EXIT_STANDALONE, + FR_SAFFIREPRO_CMD_EXIT_STANDALONE_CODE ) ) { + debugError( "setSpecificValue failed\n" ); + } +} + +void SaffireProDevice::flashLed() { int ledFlashDuration=2; @@ -570,11 +587,35 @@ } +void +SaffireProDevice::setPllLockRange(unsigned int i) { + uint32_t reg=i; + debugOutput( DEBUG_LEVEL_VERBOSE, "set PLL lock range: %d ...\n", i ); + + if ( !setSpecificValue(FR_SAFFIREPRO_CMD_ID_PLL_LOCK_RANGE, + reg ) ) { + debugError( "setSpecificValue failed\n" ); + } +} + +unsigned int +SaffireProDevice::getPllLockRange() { + uint32_t retval; + if ( !getSpecificValue(FR_SAFFIREPRO_CMD_ID_PLL_LOCK_RANGE, &retval ) ) { + debugError( "getSpecificValue failed\n" ); + return false; + } + + debugOutput( DEBUG_LEVEL_VERBOSE, + "PLL lock range: %d\n", retval ); + return retval; +} + // swiss army knife control element -SaffireProMultiControl::SaffireProMultiControl(SaffireProDevice& parent, enum eTriggerControlType t) +SaffireProMultiControl::SaffireProMultiControl(SaffireProDevice& parent, enum eMultiControlType t) : Control::Discrete() , m_Parent(parent) , m_type ( t ) {} -SaffireProMultiControl::SaffireProMultiControl(SaffireProDevice& parent, enum eTriggerControlType t, +SaffireProMultiControl::SaffireProMultiControl(SaffireProDevice& parent, enum eMultiControlType t, std::string name, std::string label, std::string descr) : Control::Discrete() @@ -594,4 +635,6 @@ case eTCT_FlashLed: m_Parent.flashLed(); return true; case eTCT_UseHighVoltageRail: m_Parent.useHighVoltageRail(v); return true; + case eTCT_ExitStandalone: m_Parent.exitStandalone(); return true; + case eTCT_PllLockRange: m_Parent.setPllLockRange(v); return true; } return false; @@ -605,4 +648,6 @@ case eTCT_FlashLed: return 0; case eTCT_UseHighVoltageRail: return m_Parent.usingHighVoltageRail(); + case eTCT_ExitStandalone: return 0; + case eTCT_PllLockRange: return m_Parent.getPllLockRange(); } return -1; Index: trunk/libffado/src/bebob/focusrite/focusrite_saffirepro.h =================================================================== --- trunk/libffado/src/bebob/focusrite/focusrite_saffirepro.h (revision 750) +++ trunk/libffado/src/bebob/focusrite/focusrite_saffirepro.h (revision 833) @@ -254,13 +254,15 @@ { public: - enum eTriggerControlType { + enum eMultiControlType { eTCT_Reboot, eTCT_FlashLed, eTCT_UseHighVoltageRail, + eTCT_ExitStandalone, + eTCT_PllLockRange, }; public: - SaffireProMultiControl(SaffireProDevice& parent, enum eTriggerControlType); - SaffireProMultiControl(SaffireProDevice& parent, enum eTriggerControlType, + SaffireProMultiControl(SaffireProDevice& parent, enum eMultiControlType); + SaffireProMultiControl(SaffireProDevice& parent, enum eMultiControlType, std::string name, std::string label, std::string descr); @@ -270,5 +272,5 @@ private: SaffireProDevice& m_Parent; - enum eTriggerControlType m_type; + enum eMultiControlType m_type; }; @@ -320,7 +322,11 @@ bool isExtClockLocked(); uint32_t getCount32(); + void exitStandalone(); void useHighVoltageRail(bool useIt); bool usingHighVoltageRail(); + unsigned int getPllLockRange(); + void setPllLockRange(unsigned int); + private: virtual bool setSamplingFrequencyDo( uint32_t ); Index: trunk/libffado/src/devicemanager.cpp =================================================================== --- trunk/libffado/src/devicemanager.cpp (revision 826) +++ trunk/libffado/src/devicemanager.cpp (revision 833) @@ -553,16 +553,16 @@ } -bool +enum DeviceManager::eWaitResult DeviceManager::waitForPeriod() { if(m_processorManager->waitForPeriod()) { - return true; + return eWR_OK; } else { debugWarning("XRUN detected\n"); // do xrun recovery if(m_processorManager->handleXrun()) { - return false; + return eWR_Xrun; } else { debugError("Could not handle XRUN\n"); - return false; + return eWR_Error; } } Index: trunk/libffado/src/bounce/bounce_avdevice.cpp =================================================================== --- trunk/libffado/src/bounce/bounce_avdevice.cpp (revision 742) +++ trunk/libffado/src/bounce/bounce_avdevice.cpp (revision 833) @@ -212,4 +212,5 @@ Streaming::Port *p=NULL; p=new Streaming::AmdtpAudioPort( + *processor, buff, direction, @@ -224,13 +225,4 @@ if (!p) { debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff); - } else { - - if (!processor->addPort(p)) { - debugWarning("Could not register port with stream processor\n"); - free(buff); - return false; - } else { - debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff); - } } free(buff); @@ -243,4 +235,5 @@ Streaming::Port *p=NULL; p=new Streaming::AmdtpMidiPort( + *processor, buff, direction, @@ -255,13 +248,4 @@ if (!p) { debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff); - } else { - - if (!processor->addPort(p)) { - debugWarning("Could not register port with stream processor\n"); - free(buff); - return false; - } else { - debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff); - } } free(buff);