Changeset 287

Show
Ignore:
Timestamp:
07/09/06 16:33:32 (18 years ago)
Author:
jwoithe
Message:

Some cleanups to the MotuStreamProcessor? source.
First pass at a stop preparation method (StreamProcessor::preparedToStop()).
Motu uses preparedToStop to write zero data to device before iso closedown.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/libfreebob-2.0/src/libstreaming/MotuStreamProcessor.cpp

    r286 r287  
    5050                unsigned int event_size) 
    5151        : TransmitStreamProcessor(port, framerate), m_event_size(event_size), 
    52         m_tx_dbc(0), m_cycle_count(-1), m_cycle_ofs(0.0), m_sph_ofs_dll(NULL) { 
     52        m_tx_dbc(0), m_cycle_count(-1), m_cycle_ofs(0.0), m_sph_ofs_dll(NULL), 
     53        m_closedown_count(-1) { 
    5354 
    5455} 
     
    6970                return false; 
    7071        } 
    71          
     72        m_closedown_count = -1; 
    7273 
    7374        return true; 
     
    99100// 
    100101// The other thing which needs to be worked out is close-down. 
    101 // Experimentation has shown that 2 or so zero packets need to be sent so no 
     102// Experimentation has shown that some zero packets need to be sent so no 
    102103// high-pitched noises are emitted at closedown and subsequent restart.  In 
    103104// the proof-of-concept code this was done by manually calling 
     
    116117        signed int i; 
    117118 
    118         // signal that we are running 
    119         // this is to allow the manager to wait untill all streams are up&running 
    120         // it can take some time before the devices start to transmit. 
    121         // if we would transmit ourselves, we'd have instant buffer underrun 
    122         // this works in cooperation with the m_disabled value 
    123          
    124         // TODO: add code here to detect that a stream is running 
    125         // NOTE: xmit streams are most likely 'always' ready 
    126         m_running=true; 
     119        // The MOTU transmit stream is 'always' ready 
     120        m_running = true; 
    127121         
    128122        // Initialise the cycle counter if this is the first time 
    129         // iso data has been requested with the stream enabled
     123        // iso data has been requested
    130124        if (!m_disabled && m_cycle_count<0) { 
    131125                m_cycle_count = cycle; 
     
    149143 
    150144        // Increment the dbc (data block count).  This is only done if the 
    151         // packet will contain events - that is, the stream is not disabled 
    152         // and we are due to send some data.  Otherwise a pad packet is sent 
    153         // which contains the DBC of the previously sent packet.  This 
    154         // regime also means that the very first packet containing data will 
    155         // have a DBC of n_events, which matches what is observed from other 
    156         // systems. 
     145        // packet will contain events - that is, we are due to send some 
     146        // data.  Otherwise a pad packet is sent which contains the DBC of 
     147        // the previously sent packet.  This regime also means that the very 
     148        // first packet containing data will have a DBC of n_events, which 
     149        // matches what is observed from other systems. 
    157150        if (!m_disabled && cycle>=m_cycle_count) { 
    158151                m_tx_dbc += n_events; 
     
    174167        // ahead of the ieee1394 cycle timer, we send a data-less packet 
    175168        // with only the 8 byte CIP-like header set up previously. 
    176         // FIXME: in disabled state, need to send a stream of zero audio data, 
    177         // not "no data".  Otherwise MOTU will emit an (approx) 10 kHz signal. 
    178169        if (m_disabled || cycle<m_cycle_count) { 
    179170                return RAW1394_ISO_OK; 
     
    183174        unsigned int read_size = n_events * m_event_size; 
    184175 
    185         // We read the packet data from a ringbuffer because of efficiency; 
    186         // it allows us to construct the packets one period at once. 
    187         if ((freebob_ringbuffer_read(m_event_buffer,(char *)(data+8),read_size)) <  
    188                                 read_size) { 
     176        // In the disabled state simply zero all data sent to the MOTU.  If 
     177        // a stream of empty packets are sent once iso streaming is enabled 
     178        // the MOTU tends to emit high-pitched audio (approx 10 kHz) for 
     179        // some reason.  This is not completely sufficient, however (zeroed 
     180        // packets must also be sent on iso closedown). 
     181 
     182        // FIXME: Currently we simply send empty packets to the MOTU when 
     183        // the stream is disabled so the "m_disabled == 0" code is never 
     184        // executed.  However, this may change in future so it's left in  
     185        // for the moment for reference. 
     186        // FIXME: Currently we don't read the buffer at all during closedown. 
     187        // We could (and silently junk the contents) if it turned out to be 
     188        // more helpful. 
     189        if (!m_disabled && m_closedown_count<0) { 
     190                // We read the packet data from a ringbuffer because of 
     191                // efficiency; it allows us to construct the packets one 
     192                // period at once. 
     193                i = freebob_ringbuffer_read(m_event_buffer,(char *)(data+8),read_size) < 
     194                        read_size; 
     195        } else { 
     196                memset(data+8, 0, read_size); 
     197                i = 0; 
     198        } 
     199        if (i == 1) { 
    189200                /* there is no more data in the ringbuffer */ 
    190201                debugWarning("Transmit buffer underrun (cycle %d, FC=%d, PC=%d)\n",  
     
    200211                retval=RAW1394_ISO_OK; 
    201212                *length += read_size; 
     213 
     214// FIXME: if we choose to read the buffer even during closedown, 
     215// here is where the data is silenced. 
     216//              if (m_closedown_count >= 0) 
     217//                      memset(data+8, 0, read_size); 
     218                if (m_closedown_count > 0) 
     219                        m_closedown_count--; 
    202220 
    203221                // Set up each frames's SPH.  Note that the (int) typecast 
     
    208226                        *quadlet = htonl( (((m_cycle_count+CYCLE_DELAY)%8000)<<12) +  
    209227                                        (int)m_cycle_ofs); 
    210 // FIXME: remove this hacked in 1 kHz test signal to analog-1 
    211 
     228// FIXME: remove this hacked in 1 kHz test signal to analog-1 when testing 
     229// is complete.  Note that the tone is *not* added during closedown. 
     230if (m_closedown_count<0) { 
    212231signed int val; 
    213 val = 0x7fffff*sin(1000.0*2.0*M_PI*(m_cycle_count+((m_cycle_ofs)/3072.0))/8000.0); 
     232val = (int)(0x7fffff*sin(1000.0*2.0*M_PI*(m_cycle_count+((m_cycle_ofs)/3072.0))/8000.0)); 
    214233*(data+8+i*m_event_size+16) = (val >> 16) & 0xff; 
    215234*(data+8+i*m_event_size+17) = (val >> 8) & 0xff; 
     
    223242                        } 
    224243                } 
    225 #if 0 
    226 //if (cycle==10) { 
    227 if (m_cycle_count==7999 || m_cycle_count==0) { 
    228 int j; 
    229   for (j=0; j<n_events; j++) { 
    230     for (i=0; i<25; i++) 
    231       fprintf(stderr,"%02hhx ",*(data+8+j*dbs*4+i)); 
    232     fprintf(stderr,"\n"); 
    233   } 
    234 
    235 #endif 
     244 
    236245                // Process all ports that should be handled on a per-packet base 
    237246                // this is MIDI for AMDTP (due to the need of DBC, which is lost  
     
    453462        int xrun; 
    454463        unsigned int offset=0; 
    455  
    456 // FIXME: just return until we've got the transmit side of things functional 
    457 //return true; 
    458464 
    459465        freebob_ringbuffer_data_t vec[2]; 
     
    667673                       unsigned int offset, unsigned int nevents) { 
    668674        unsigned int j=0; 
    669 #if 0 
    670         unsigned char *target = (unsigned char *)data + p->getPosition(); 
    671  
    672 // offset is offset into the port buffers 
    673 //quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); 
    674 //assert(nevents + offset <= p->getBufferSize()); 
    675 //buffer+=offset; 
    676  
    677  
    678 // FIXME: use the form of the silence version here for testing 
    679         switch (p->getDataType()) { 
    680         default: 
    681         case Port::E_Int24: 
    682         case Port::E_Float: 
    683 // send silence to all outputs for now 
    684                 for (j = 0; j < nevents; j++) { 
    685 signed int val = 0; 
    686   val = 0; 
    687                         *target = (val >> 16) & 0xff; 
    688                         *(target+1) = (val >> 8) & 0xff; 
    689                         *(target+2) = val & 0xff; 
    690                         target += m_event_size; 
    691                 } 
    692                 break; 
    693         } 
    694  
    695 #endif 
    696675 
    697676        // Use char here since the target address won't necessarily be  
    698677        // aligned; use of an unaligned quadlet_t may cause issues on certain 
    699         // architectures. 
     678        // architectures.  Besides, the target (data going directly to the MOTU) 
     679        // isn't structured in quadlets anyway; it mainly consists of packed 
     680        // 24-bit integers. 
    700681        unsigned char *target; 
    701682        target = (unsigned char *)data + p->getPosition(); 
     
    735716 
    736717                                for(j = 0; j < nevents; j += 1) { // decode max nsamples                 
    737                                         unsigned int v = *buffer * multiplier
     718                                        unsigned int v = (int)(*buffer * multiplier)
    738719                                        *target = (v >> 16) & 0xff; 
    739720                                        *(target+1) = (v >> 8) & 0xff; 
     
    747728        } 
    748729 
    749         return 0; 
    750  
    751  
    752  
    753 /* 
    754     quadlet_t *target_event; 
    755  
    756     target_event=(quadlet_t *)(data + p->getPosition()); 
    757  
    758     switch(p->getDataType()) { 
    759         default: 
    760         case Port::E_Int24: 
    761             { 
    762                 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); 
    763  
    764                 assert(nevents + offset <= p->getBufferSize()); 
    765  
    766                 buffer+=offset; 
    767  
    768                 for(j = 0; j < nevents; j += 1) { // decode max nsamples 
    769                     *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000); 
    770                     buffer++; 
    771                     target_event += m_dimension; 
    772                 } 
    773             } 
    774             break; 
    775         case Port::E_Float: 
    776             { 
    777                 const float multiplier = (float)(0x7FFFFF00); 
    778                 float *buffer=(float *)(p->getBufferAddress()); 
    779  
    780                 assert(nevents + offset <= p->getBufferSize()); 
    781  
    782                 buffer+=offset; 
    783  
    784                 for(j = 0; j < nevents; j += 1) { // decode max nsamples                 
    785      
    786                     // don't care for overflow 
    787                     float v = *buffer * multiplier;  // v: -231 .. 231 
    788                     unsigned int tmp = ((int)v); 
    789                     *target_event = htonl((tmp >> 8) | 0x40000000); 
    790                      
    791                     buffer++; 
    792                     target_event += m_dimension; 
    793                 } 
    794             } 
    795             break; 
    796     } 
    797 */ 
    798730        return 0; 
    799731} 
     
    816748 
    817749        return 0; 
     750} 
     751 
     752bool MotuTransmitStreamProcessor::preparedForStop() { 
     753 
     754        // FIXME: ideally we want to include a condition which tests if the 
     755        // stream shutdown is in response to an xrun due to a problem at 
     756        // startup, and unconditionally return true.  This saves a few 
     757        // seconds delay since under these conditions the iso transmit 
     758        // callback doesn't appear to be called and therefore 
     759        // m_closedown_count is never decremented.  We can't just test for 
     760        // an xrun however since sometimes these can occur "normally" during 
     761        // shutdown.  This is probably all tied up with the sync recovery 
     762        // issue which hasn't really been exported yet. 
     763        if (m_disabled || !isRunning()) 
     764                return true; 
     765 
     766        if (m_closedown_count < 0) { 
     767                // No closedown has been initiated, so start one now.  Set 
     768                // the closedown count to the number of zero packets which 
     769                // will be sent to the MOTU before closing off the iso 
     770                // streams.  FIXME: 128 is the experimentally-determined 
     771                // figure for 48 kHz.  Other rates may require other 
     772                // settings. 
     773                m_closedown_count = 128; 
     774                return false; 
     775        } 
     776 
     777        // We are "go" for closedown once all requested zero packets 
     778        // (initiated by a previous call to this function) have been sent to 
     779        // the MOTU. 
     780        return m_closedown_count == 0; 
    818781} 
    819782 
     
    12651228//      printf("****************\n"); 
    12661229 
    1267         // Use char here since a port's source address won't necessarily be  
    1268         // aligned; use of an unaligned quadlet_t may cause issues on certain 
    1269         // architectures. 
     1230        // Use char here since a port's source address won't necessarily be 
     1231        // aligned; use of an unaligned quadlet_t may cause issues on 
     1232        // certain architectures.  Besides, the source (data coming directly 
     1233        // from the MOTU) isn't structured in quadlets anyway; it mainly 
     1234        // consists of packed 24-bit integers. 
     1235 
    12701236        unsigned char *src_data; 
    12711237        src_data = (unsigned char *)data + p->getPosition(); 
  • branches/libfreebob-2.0/src/libstreaming/MotuStreamProcessor.h

    r283 r287  
    7474        void set_sph_ofs_dll(FreebobUtil::DelayLockedLoop *dll) {m_sph_ofs_dll=dll;}; 
    7575 
     76        virtual bool preparedForStop(); 
     77 
    7678protected: 
    7779 
     
    9799        // not dispose of it. 
    98100        FreebobUtil::DelayLockedLoop *m_sph_ofs_dll; 
     101 
     102        // Used to keep track of the close-down zeroing of output data 
     103        signed int m_closedown_count; 
    99104 
    100105    bool prefill(); 
  • branches/libfreebob-2.0/src/libstreaming/StreamProcessor.h

    r268 r287  
    111111        virtual void setVerboseLevel(int l); 
    112112 
     113        virtual bool preparedForStop() {return true;}; 
     114 
    113115protected: 
    114116         
  • branches/libfreebob-2.0/src/libstreaming/StreamProcessorManager.cpp

    r267 r287  
    469469        assert(m_isoManager); 
    470470        assert(m_streamingThread); 
     471 
     472        debugOutput( DEBUG_LEVEL_VERBOSE, "Waiting for all StreamProcessors to prepare to stop...\n"); 
     473        // Most stream processors can just stop without special treatment.  However, some 
     474        // (like the MOTU) need to do a few things before it's safe to turn off the iso 
     475        // handling. 
     476        int wait_cycles=2000; // two seconds ought to be sufficient 
     477        bool allReady = false; 
     478        while (!allReady && wait_cycles) { 
     479                wait_cycles--; 
     480                allReady = true; 
     481                 
     482                for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 
     483                        it != m_ReceiveProcessors.end(); 
     484                        ++it ) { 
     485                        if(!(*it)->preparedForStop()) allReady = false; 
     486                } 
     487         
     488                for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 
     489                        it != m_TransmitProcessors.end(); 
     490                        ++it ) { 
     491                        if(!(*it)->preparedForStop()) allReady = false; 
     492                } 
     493                usleep(1000); 
     494        } 
     495 
     496 
    471497        debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping thread...\n"); 
    472498