- Timestamp:
- 07/09/06 16:33:32 (18 years ago)
- Files:
-
- branches/libfreebob-2.0/src/libstreaming/MotuStreamProcessor.cpp (modified) (16 diffs)
- branches/libfreebob-2.0/src/libstreaming/MotuStreamProcessor.h (modified) (2 diffs)
- branches/libfreebob-2.0/src/libstreaming/StreamProcessor.h (modified) (1 diff)
- branches/libfreebob-2.0/src/libstreaming/StreamProcessorManager.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/libfreebob-2.0/src/libstreaming/MotuStreamProcessor.cpp
r286 r287 50 50 unsigned int event_size) 51 51 : 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) { 53 54 54 55 } … … 69 70 return false; 70 71 } 71 72 m_closedown_count = -1; 72 73 73 74 return true; … … 99 100 // 100 101 // The other thing which needs to be worked out is close-down. 101 // Experimentation has shown that 2 or sozero packets need to be sent so no102 // Experimentation has shown that some zero packets need to be sent so no 102 103 // high-pitched noises are emitted at closedown and subsequent restart. In 103 104 // the proof-of-concept code this was done by manually calling … … 116 117 signed int i; 117 118 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; 127 121 128 122 // 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. 130 124 if (!m_disabled && m_cycle_count<0) { 131 125 m_cycle_count = cycle; … … 149 143 150 144 // 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. 157 150 if (!m_disabled && cycle>=m_cycle_count) { 158 151 m_tx_dbc += n_events; … … 174 167 // ahead of the ieee1394 cycle timer, we send a data-less packet 175 168 // 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.178 169 if (m_disabled || cycle<m_cycle_count) { 179 170 return RAW1394_ISO_OK; … … 183 174 unsigned int read_size = n_events * m_event_size; 184 175 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) { 189 200 /* there is no more data in the ringbuffer */ 190 201 debugWarning("Transmit buffer underrun (cycle %d, FC=%d, PC=%d)\n", … … 200 211 retval=RAW1394_ISO_OK; 201 212 *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--; 202 220 203 221 // Set up each frames's SPH. Note that the (int) typecast … … 208 226 *quadlet = htonl( (((m_cycle_count+CYCLE_DELAY)%8000)<<12) + 209 227 (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. 230 if (m_closedown_count<0) { 212 231 signed int val; 213 val = 0x7fffff*sin(1000.0*2.0*M_PI*(m_cycle_count+((m_cycle_ofs)/3072.0))/8000.0);232 val = (int)(0x7fffff*sin(1000.0*2.0*M_PI*(m_cycle_count+((m_cycle_ofs)/3072.0))/8000.0)); 214 233 *(data+8+i*m_event_size+16) = (val >> 16) & 0xff; 215 234 *(data+8+i*m_event_size+17) = (val >> 8) & 0xff; … … 223 242 } 224 243 } 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 236 245 // Process all ports that should be handled on a per-packet base 237 246 // this is MIDI for AMDTP (due to the need of DBC, which is lost … … 453 462 int xrun; 454 463 unsigned int offset=0; 455 456 // FIXME: just return until we've got the transmit side of things functional457 //return true;458 464 459 465 freebob_ringbuffer_data_t vec[2]; … … 667 673 unsigned int offset, unsigned int nevents) { 668 674 unsigned int j=0; 669 #if 0670 unsigned char *target = (unsigned char *)data + p->getPosition();671 672 // offset is offset into the port buffers673 //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 testing679 switch (p->getDataType()) {680 default:681 case Port::E_Int24:682 case Port::E_Float:683 // send silence to all outputs for now684 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 #endif696 675 697 676 // Use char here since the target address won't necessarily be 698 677 // 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. 700 681 unsigned char *target; 701 682 target = (unsigned char *)data + p->getPosition(); … … 735 716 736 717 for(j = 0; j < nevents; j += 1) { // decode max nsamples 737 unsigned int v = *buffer * multiplier;718 unsigned int v = (int)(*buffer * multiplier); 738 719 *target = (v >> 16) & 0xff; 739 720 *(target+1) = (v >> 8) & 0xff; … … 747 728 } 748 729 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 nsamples769 *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 nsamples785 786 // don't care for overflow787 float v = *buffer * multiplier; // v: -231 .. 231788 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 */798 730 return 0; 799 731 } … … 816 748 817 749 return 0; 750 } 751 752 bool 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; 818 781 } 819 782 … … 1265 1228 // printf("****************\n"); 1266 1229 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 1270 1236 unsigned char *src_data; 1271 1237 src_data = (unsigned char *)data + p->getPosition(); branches/libfreebob-2.0/src/libstreaming/MotuStreamProcessor.h
r283 r287 74 74 void set_sph_ofs_dll(FreebobUtil::DelayLockedLoop *dll) {m_sph_ofs_dll=dll;}; 75 75 76 virtual bool preparedForStop(); 77 76 78 protected: 77 79 … … 97 99 // not dispose of it. 98 100 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; 99 104 100 105 bool prefill(); branches/libfreebob-2.0/src/libstreaming/StreamProcessor.h
r268 r287 111 111 virtual void setVerboseLevel(int l); 112 112 113 virtual bool preparedForStop() {return true;}; 114 113 115 protected: 114 116 branches/libfreebob-2.0/src/libstreaming/StreamProcessorManager.cpp
r267 r287 469 469 assert(m_isoManager); 470 470 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 471 497 debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping thread...\n"); 472 498