Changeset 2078

Show
Ignore:
Timestamp:
03/10/12 06:03:53 (12 years ago)
Author:
jwoithe
Message:

A first pass at infrastructure required to support jack's runtime setbufsize functionality. It has been tested with exactly one interface (RME Fireface-800) and it seems to work, but there's stacks which can go wrong so wider testing is encouraged. Note that to make use of this a revised firewire jack driver will be required. I'm going to talk to the jack guys about how to proceed with this (it's slightly tricky because the libffado API is changed by this patch to add a new function - ffado_streaming_set_period_size()).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/libffado/libffado/ffado.h

    r1928 r2078  
    258258 
    259259/** 
     260 * This permits the setting of the period size at some time after  
     261 * initialisation.  The primary use of this function is to support the 
     262 * setbufsize functionality of JACK. 
     263 * 
     264 * @param dev the ffado device 
     265 * @param period the new period size 
     266 * @return 0 on success, non-zero if an error occurred 
     267 */ 
     268int ffado_streaming_set_period_size(ffado_device_t *dev, unsigned int period); 
     269 
     270/** 
    260271 * preparation should be done after setting all per-stream parameters 
    261272 * the way you want them. being buffer data type etc... 
  • trunk/libffado/src/devicemanager.cpp

    r2074 r2078  
    10091009 
    10101010bool 
     1011DeviceManager::setPeriodSize(unsigned int period) { 
     1012    // Useful for cases where only the period size needs adjusting 
     1013    m_processorManager->setPeriodSize(period); 
     1014    return true; 
     1015} 
     1016 
     1017bool 
    10111018DeviceManager::setStreamingParams(unsigned int period, unsigned int rate, unsigned int nb_buffers) { 
    10121019    m_processorManager->setPeriodSize(period); 
  • trunk/libffado/src/devicemanager.h

    r1763 r2078  
    9696    bool resetStreaming(); 
    9797    enum eWaitResult waitForPeriod(); 
     98    bool setPeriodSize(unsigned int period); 
    9899    bool setStreamingParams(unsigned int period, unsigned int rate, unsigned int nb_buffers); 
    99100 
  • trunk/libffado/src/ffado.cpp

    r1498 r2078  
    184184    // we are ready! 
    185185    return dev; 
     186} 
     187 
     188int ffado_streaming_set_period_size(ffado_device_t *dev, unsigned int period) { 
     189    if (!dev->m_deviceManager->setPeriodSize(period)) 
     190    { 
     191        debugFatal( "Could not set period size of device manager\n" ); 
     192        return -1; 
     193    } 
     194    return 0; 
    186195} 
    187196 
  • trunk/libffado/src/libstreaming/generic/Port.cpp

    r1498 r2078  
    9191bool Port::setBufferSize(unsigned int newsize) { 
    9292    debugOutput( DEBUG_LEVEL_VERBOSE, "Setting buffersize to %d for port %s\n",newsize,m_Name.c_str()); 
    93     if (m_State != E_Created) { 
    94         debugFatal("Port (%s) not in E_Created state: %d\n",m_Name.c_str(),m_State); 
     93    if (m_State != E_Created && m_disabled == false) { 
     94        debugFatal("Port (%s) not in E_Created/disabled state: %d\n",m_Name.c_str(),m_State); 
    9595        return false; 
    9696    } 
  • trunk/libffado/src/libstreaming/generic/StreamProcessor.cpp

    r1972 r2078  
    9595 
    9696bool 
     97StreamProcessor::periodSizeChanged(unsigned int new_periodsize) { 
     98    // This is called by the StreamProcessorManager whenever the period size 
     99    // is changed via setPeriodSize().  If the stream processor needs to do 
     100    // anything in response it can be done in this method.  Buffer size 
     101    // changes should only ever be made when streaming is not active. 
     102    // 
     103    // Return false if there was a problem dealing with the resize. 
     104    if (m_state!=ePS_Stopped && m_state!=ePS_Created) { 
     105        debugOutput(DEBUG_LEVEL_WARNING, "(%p) period change should only be done with streaming stopped\n", this); 
     106        return false; 
     107    } 
     108 
     109    // make the scratch buffer one period of frames long 
     110    m_scratch_buffer_size_bytes = new_periodsize * getEventsPerFrame() * getEventSize(); 
     111    debugOutput( DEBUG_LEVEL_VERBOSE, " Allocate scratch buffer of %zd quadlets\n", m_scratch_buffer_size_bytes); 
     112    if(m_scratch_buffer) delete[] m_scratch_buffer; 
     113    m_scratch_buffer = new byte_t[m_scratch_buffer_size_bytes]; 
     114    if(m_scratch_buffer == NULL) { 
     115        debugFatal("Could not allocate scratch buffer\n"); 
     116        return false; 
     117    } 
     118 
     119    // set the parameters of ports we can: 
     120    // we want the audio ports to be period buffered, 
     121    // and the midi ports to be packet buffered 
     122    for ( PortVectorIterator it = m_Ports.begin(); 
     123        it != m_Ports.end(); 
     124        ++it ) 
     125    { 
     126        debugOutput(DEBUG_LEVEL_VERBOSE, "Setting up port %s\n",(*it)->getName().c_str()); 
     127        if(!(*it)->setBufferSize(m_StreamProcessorManager.getPeriodSize())) { 
     128            debugFatal("Could not set buffer size to %d\n",m_StreamProcessorManager.getPeriodSize()); 
     129            return false; 
     130        } 
     131    } 
     132 
     133    if (!setupDataBuffer()) { 
     134        debugFatal("Could not setup data buffer\n"); 
     135        return false; 
     136    } 
     137 
     138    return updateState(); 
     139} 
     140 
     141bool 
    97142StreamProcessor::handleBusResetDo() 
    98143{ 
     
    168213 * Buffer management and manipulation          * 
    169214 ***********************************************/ 
     215bool 
     216StreamProcessor::setupDataBuffer() { 
     217    assert(m_data_buffer); 
     218 
     219    unsigned int ringbuffer_size_frames = m_StreamProcessorManager.getNbBuffers() * m_StreamProcessorManager.getPeriodSize(); 
     220    ringbuffer_size_frames += m_extra_buffer_frames; 
     221    ringbuffer_size_frames += 1; // to ensure that we can fit it all in there 
     222 
     223    bool result = true; 
     224 
     225    m_correct_last_timestamp = false; 
     226         
     227    // initialize internal buffer 
     228    result &= m_data_buffer->setBufferSize(ringbuffer_size_frames); 
     229 
     230    result &= m_data_buffer->setEventSize( getEventSize() ); 
     231    result &= m_data_buffer->setEventsPerFrame( getEventsPerFrame() ); 
     232    if(getType() == ePT_Receive) { 
     233        result &= m_data_buffer->setUpdatePeriod( getNominalFramesPerPacket() ); 
     234    } else { 
     235        result &= m_data_buffer->setUpdatePeriod( m_StreamProcessorManager.getPeriodSize() ); 
     236    } 
     237    // Completing the buffer's setup and calling the prepare() method is not 
     238    // applicable unless the nominal rate (m_ticks_per_frame) has been 
     239    // configured.  This may not be the case when setupDataBuffer() is 
     240    // called from prepare() via periodSizeChanged(), but will be when called 
     241    // from doStop() and from periodSizeChanged() via the stream processor's 
     242    // setPeriodSize() method. 
     243    if (m_ticks_per_frame > 0) { 
     244        result &= m_data_buffer->setNominalRate(m_ticks_per_frame); 
     245        result &= m_data_buffer->setWrapValue(128L * TICKS_PER_SECOND); 
     246        result &= m_data_buffer->setBandwidth(STREAMPROCESSOR_DLL_FAST_BW_HZ / (double)TICKS_PER_SECOND); 
     247 
     248        result &= m_data_buffer->prepare(); // FIXME: the name 
     249 
     250        debugOutput(DEBUG_LEVEL_VERBOSE, "DLL info: nominal tpf: %f, update period: %d, bandwidth: %e 1/ticks (%e Hz)\n",  
     251                    m_data_buffer->getNominalRate(), m_data_buffer->getUpdatePeriod(), m_data_buffer->getBandwidth(), m_data_buffer->getBandwidth() * TICKS_PER_SECOND); 
     252    } 
     253 
     254    return result; 
     255} 
     256 
    170257void 
    171258StreamProcessor::getBufferHeadTimestamp(ffado_timestamp_t *ts, signed int *fc) 
     
    10701157    debugOutput( DEBUG_LEVEL_VERBOSE, "Prepare SP (%p)...\n", this); 
    10711158 
    1072     // make the scratch buffer one period of frames long 
    1073     m_scratch_buffer_size_bytes = m_StreamProcessorManager.getPeriodSize() * getEventsPerFrame() * getEventSize(); 
    1074     debugOutput( DEBUG_LEVEL_VERBOSE, " Allocate scratch buffer of %zd quadlets\n", m_scratch_buffer_size_bytes); 
    1075     if(m_scratch_buffer) delete[] m_scratch_buffer; 
    1076     m_scratch_buffer = new byte_t[m_scratch_buffer_size_bytes]; 
    1077     if(m_scratch_buffer == NULL) { 
    1078         debugFatal("Could not allocate scratch buffer\n"); 
     1159    if (periodSizeChanged(m_StreamProcessorManager.getPeriodSize()) == false) 
    10791160        return false; 
    1080     } 
    1081  
    1082     // set the parameters of ports we can: 
    1083     // we want the audio ports to be period buffered, 
    1084     // and the midi ports to be packet buffered 
    1085     for ( PortVectorIterator it = m_Ports.begin(); 
    1086         it != m_Ports.end(); 
    1087         ++it ) 
    1088     { 
    1089         debugOutput(DEBUG_LEVEL_VERBOSE, "Setting up port %s\n",(*it)->getName().c_str()); 
    1090         if(!(*it)->setBufferSize(m_StreamProcessorManager.getPeriodSize())) { 
    1091             debugFatal("Could not set buffer size to %d\n",m_StreamProcessorManager.getPeriodSize()); 
    1092             return false; 
    1093         } 
    1094     } 
     1161 
    10951162    // the API specific settings of the ports should already be set, 
    10961163    // as this is called from the processorManager->prepare() 
     
    13551422 
    13561423    float ticks_per_frame; 
    1357     unsigned int ringbuffer_size_frames = m_StreamProcessorManager.getNbBuffers() * m_StreamProcessorManager.getPeriodSize(); 
    1358     ringbuffer_size_frames += m_extra_buffer_frames; 
    1359     ringbuffer_size_frames += 1; // to ensure that we can fit it all in there 
    13601424 
    13611425    debugOutput(DEBUG_LEVEL_VERBOSE, "Enter from state: %s\n", ePSToString(m_state)); 
     
    13721436            debugOutput(DEBUG_LEVEL_VERBOSE, "Initializing remote ticks/frame to %f\n", ticks_per_frame); 
    13731437         
    1374             // initialize internal buffer 
    1375             result &= m_data_buffer->setBufferSize(ringbuffer_size_frames); 
    1376          
    1377             result &= m_data_buffer->setEventSize( getEventSize() ); 
    1378             result &= m_data_buffer->setEventsPerFrame( getEventsPerFrame() ); 
    1379             if(getType() == ePT_Receive) { 
    1380                 result &= m_data_buffer->setUpdatePeriod( getNominalFramesPerPacket() ); 
    1381             } else { 
    1382                 result &= m_data_buffer->setUpdatePeriod( m_StreamProcessorManager.getPeriodSize() ); 
    1383             } 
    1384             result &= m_data_buffer->setNominalRate(ticks_per_frame); 
    1385             result &= m_data_buffer->setWrapValue(128L * TICKS_PER_SECOND); 
    1386             result &= m_data_buffer->setBandwidth(STREAMPROCESSOR_DLL_FAST_BW_HZ / (double)TICKS_PER_SECOND); 
    1387             result &= m_data_buffer->prepare(); // FIXME: the name 
    1388  
    1389             debugOutput(DEBUG_LEVEL_VERBOSE, "DLL info: nominal tpf: %f, update period: %d, bandwidth: %e 1/ticks (%e Hz)\n",  
    1390                         m_data_buffer->getNominalRate(), m_data_buffer->getUpdatePeriod(), m_data_buffer->getBandwidth(), m_data_buffer->getBandwidth() * TICKS_PER_SECOND); 
     1438            result &= setupDataBuffer(); 
    13911439            break; 
    13921440        case ePS_DryRunning: 
  • trunk/libffado/src/libstreaming/generic/StreamProcessor.h

    r1972 r2078  
    6363    ///> returns the type of the streamprocessor 
    6464    virtual enum eProcessorType getType() { return m_processor_type; }; 
     65 
     66    ///> notification of a buffer size change 
     67    virtual bool periodSizeChanged(unsigned int new_periodsize); 
    6568private: 
    6669    // this can only be set by the constructor 
     
    299302//--- data buffering and accounting 
    300303public: 
     304    bool setupDataBuffer(); 
    301305    void getBufferHeadTimestamp ( ffado_timestamp_t *ts, signed int *fc ); 
    302306    void getBufferTailTimestamp ( ffado_timestamp_t *ts, signed int *fc ); 
  • trunk/libffado/src/libstreaming/StreamProcessorManager.cpp

    r1998 r2078  
    307307} 
    308308 
     309void StreamProcessorManager::setPeriodSize(unsigned int period) { 
     310    // This method is called early in the initialisation sequence to set the 
     311    // initial period size.  However, at that point in time the stream 
     312    // processors haven't been registered so they won't have their buffers 
     313    // configured from here.  The initial allocation of the stream processor 
     314    // (SP) buffers happens from within the SP prepare() method. 
     315    // 
     316    // SP period size changes will normally only be acted on from here 
     317    // if the change comes about due to a runtime change in the buffer size, 
     318    // as happens via jack's setbufsize facility for example. 
     319 
     320    if (period == m_period) 
     321        return; 
     322 
     323    debugOutput( DEBUG_LEVEL_VERBOSE, "Setting period size to %d (was %d)\n", period, m_period); 
     324    m_period = period; 
     325 
     326    for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 
     327          it != m_ReceiveProcessors.end(); 
     328          ++it ) 
     329    { 
     330        if ((*it)->periodSizeChanged(period) == false) 
     331            debugWarning("receive stream processor %p couldn't set period size\n", *it); 
     332    } 
     333    for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 
     334          it != m_TransmitProcessors.end(); 
     335          ++it ) 
     336    { 
     337        if ((*it)->periodSizeChanged(period) == false) 
     338            debugWarning("transmit stream processor %p couldn't set period size\n", *it); 
     339    } 
     340 
     341    // Keep the activity timeout in sync with the new period size.  See 
     342    // also comments about this in prepare(). 
     343    if (m_nominal_framerate > 0) { 
     344        int timeout_usec = 2*1000LL * 1000LL * m_period / m_nominal_framerate; 
     345        debugOutput(DEBUG_LEVEL_VERBOSE, "setting activity timeout to %d\n", timeout_usec); 
     346        setActivityWaitTimeoutUsec(timeout_usec); 
     347    } 
     348} 
     349 
    309350bool StreamProcessorManager::setSyncSource(StreamProcessor *s) { 
    310351    debugOutput( DEBUG_LEVEL_VERBOSE, "Setting sync source to (%p)\n", s); 
  • trunk/libffado/src/libstreaming/StreamProcessorManager.h

    r1972 r2078  
    8585    bool unregisterProcessor(StreamProcessor *processor); ///< stop managing a streamprocessor 
    8686 
    87     void setPeriodSize(unsigned int period) 
    88             {m_period = period;}; 
     87    void setPeriodSize(unsigned int period); 
    8988    unsigned int getPeriodSize() 
    9089            {return m_period;}; 
  • trunk/libffado/src/libutil/TimestampedBuffer.cpp

    r1981 r2078  
    396396    m_cluster_size = m_events_per_frame * m_event_size; 
    397397    m_process_block_size = m_cluster_size * FRAMES_PER_PROCESS_BLOCK; 
     398    if (m_process_buffer != NULL) 
     399        free(m_process_buffer); 
    398400    if( !(m_process_buffer=(char *)calloc(m_process_block_size, 1))) { 
    399401            debugFatal("Could not allocate temporary cluster buffer\n");