Changeset 733
- Timestamp:
- 11/28/07 03:25:27 (13 years ago)
- Files:
-
- branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.cpp (modified) (4 diffs)
- branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.h (modified) (1 diff)
- branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp (modified) (1 diff)
- branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.h (modified) (1 diff)
- branches/ppalmers-streaming/src/libstreaming/generic/StreamProcessor.cpp (modified) (2 diffs)
- branches/ppalmers-streaming/src/libstreaming/generic/StreamProcessor.h (modified) (4 diffs)
- branches/ppalmers-streaming/src/libstreaming/motu/MotuReceiveStreamProcessor.cpp (modified) (12 diffs)
- branches/ppalmers-streaming/src/libstreaming/motu/MotuReceiveStreamProcessor.h (modified) (5 diffs)
- branches/ppalmers-streaming/src/libstreaming/motu/MotuStreamProcessor-old.cpp (deleted)
- branches/ppalmers-streaming/src/libstreaming/motu/MotuStreamProcessor-old.h (deleted)
- branches/ppalmers-streaming/src/libstreaming/motu/MotuTransmitStreamProcessor.cpp (modified) (10 diffs)
- branches/ppalmers-streaming/src/libstreaming/motu/MotuTransmitStreamProcessor.h (modified) (6 diffs)
- branches/ppalmers-streaming/src/motu/motu_avdevice.cpp (modified) (3 diffs)
- branches/ppalmers-streaming/src/motu/motu_avdevice.h (modified) (1 diff)
- branches/ppalmers-streaming/src/SConscript (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.cpp
r729 r733 31 31 #include <assert.h> 32 32 33 // in ticks34 // as per AMDTP2.1:35 // 354.17us + 125us @ 24.576ticks/usec = 11776.08192 ticks36 #define DEFAULT_TRANSFER_DELAY (11776U)37 38 #define TRANSMIT_TRANSFER_DELAY DEFAULT_TRANSFER_DELAY39 40 33 namespace Streaming { 41 34 … … 46 39 , m_dimension( dimension ) 47 40 {} 48 49 unsigned int50 AmdtpReceiveStreamProcessor::getNominalPacketsNeeded(unsigned int nframes)51 {52 unsigned int nominal_frames_per_second = m_manager->getNominalRate();53 uint64_t nominal_ticks_per_frame = TICKS_PER_SECOND / nominal_frames_per_second;54 uint64_t nominal_ticks = nominal_ticks_per_frame * nframes;55 uint64_t nominal_packets = nominal_ticks / TICKS_PER_CYCLE;56 return nominal_packets;57 }58 59 unsigned int60 AmdtpReceiveStreamProcessor::getPacketsPerPeriod()61 {62 return getNominalPacketsNeeded(m_manager->getPeriodSize());63 }64 41 65 42 bool AmdtpReceiveStreamProcessor::prepareChild() { … … 206 183 if(decodeMBLAEventsToPort(static_cast<AmdtpAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) { 207 184 debugWarning("Could not decode packet MBLA to port %s",(*it)->getName().c_str()); 208 no_problem=false;209 }210 break;211 case AmdtpPortInfo::E_SPDIF: // still unimplemented212 break;213 /* for this processor, midi is a packet based port214 case AmdtpPortInfo::E_Midi:215 break;*/216 default: // ignore217 break;218 }219 }220 return no_problem;221 }222 223 /**224 * @brief write silence events to the stream ringbuffers.225 */226 bool AmdtpReceiveStreamProcessor::provideSilenceBlock(unsigned int nevents, unsigned int offset)227 {228 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "(%p)->proviceSilenceBlock(%u, %u)\n", this, nevents, offset);229 230 bool no_problem=true;231 232 for ( PortVectorIterator it = m_PeriodPorts.begin();233 it != m_PeriodPorts.end();234 ++it )235 {236 if((*it)->isDisabled()) {continue;};237 //FIXME: make this into a static_cast when not DEBUG?238 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);239 assert(pinfo); // this should not fail!!240 241 switch(pinfo->getFormat()) {242 case AmdtpPortInfo::E_MBLA:243 if(provideSilenceToPort(static_cast<AmdtpAudioPort *>(*it), offset, nevents)) {244 debugWarning("Could not put silence into to port %s",(*it)->getName().c_str());245 185 no_problem=false; 246 186 } … … 368 308 return 0; 369 309 } 370 371 int372 AmdtpReceiveStreamProcessor::provideSilenceToPort(373 AmdtpAudioPort *p, unsigned int offset, unsigned int nevents)374 {375 unsigned int j=0;376 switch(p->getDataType()) {377 default:378 case Port::E_Int24:379 {380 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());381 assert(nevents + offset <= p->getBufferSize());382 buffer+=offset;383 384 for(j = 0; j < nevents; j += 1) { // decode max nsamples385 *(buffer)=0;386 buffer++;387 }388 }389 break;390 case Port::E_Float:391 {392 float *buffer=(float *)(p->getBufferAddress());393 assert(nevents + offset <= p->getBufferSize());394 buffer+=offset;395 396 for(j = 0; j < nevents; j += 1) { // decode max nsamples397 *buffer = 0.0;398 buffer++;399 }400 }401 break;402 }403 return 0;404 }405 406 310 } // end of namespace Streaming branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.h
r729 r733 96 96 virtual unsigned int getNominalFramesPerPacket() 97 97 {return m_syt_interval;}; 98 virtual unsigned int getPacketsPerPeriod();99 virtual unsigned int getNominalPacketsNeeded(unsigned int nframes);100 98 101 99 protected: 102 100 bool processReadBlock(char *data, unsigned int nevents, unsigned int offset); 103 bool provideSilenceBlock(unsigned int nevents, unsigned int offset);104 101 105 102 private: 106 103 bool decodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc); 107 108 104 int decodeMBLAEventsToPort(AmdtpAudioPort *, quadlet_t *data, unsigned int offset, unsigned int nevents); 109 int provideSilenceToPort(AmdtpAudioPort *p, unsigned int offset, unsigned int nevents);110 105 111 106 int m_dimension; 112 107 unsigned int m_syt_interval; 113 114 uint64_t m_last_syt; /// FIXME:debug115 uint64_t m_last_now; /// FIXME:debug116 108 }; 117 109 branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp
r729 r733 345 345 } 346 346 347 unsigned int348 AmdtpTransmitStreamProcessor::getNominalPacketsNeeded(unsigned int nframes)349 {350 unsigned int nominal_frames_per_second = m_manager->getNominalRate();351 uint64_t nominal_ticks_per_frame = TICKS_PER_SECOND / nominal_frames_per_second;352 uint64_t nominal_ticks = nominal_ticks_per_frame * nframes;353 uint64_t nominal_packets = nominal_ticks / TICKS_PER_CYCLE;354 return nominal_packets;355 }356 357 unsigned int358 AmdtpTransmitStreamProcessor::getPacketsPerPeriod()359 {360 return getNominalPacketsNeeded(m_manager->getPeriodSize());361 }362 363 347 bool AmdtpTransmitStreamProcessor::prepareChild() 364 348 { branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.h
r729 r733 103 103 virtual unsigned int getNominalFramesPerPacket() 104 104 {return m_syt_interval;}; 105 virtual unsigned int getPacketsPerPeriod();106 virtual unsigned int getNominalPacketsNeeded(unsigned int nframes);107 105 108 106 protected: branches/ppalmers-streaming/src/libstreaming/generic/StreamProcessor.cpp
r729 r733 71 71 return (int)(m_handler->getWakeupInterval() * TICKS_PER_CYCLE); 72 72 } 73 } 74 75 unsigned int 76 StreamProcessor::getNominalPacketsNeeded(unsigned int nframes) 77 { 78 unsigned int nominal_frames_per_second = m_manager->getNominalRate(); 79 uint64_t nominal_ticks_per_frame = TICKS_PER_SECOND / nominal_frames_per_second; 80 uint64_t nominal_ticks = nominal_ticks_per_frame * nframes; 81 uint64_t nominal_packets = nominal_ticks / TICKS_PER_CYCLE; 82 return nominal_packets; 73 83 } 74 84 … … 705 715 return result; 706 716 } 717 } 718 719 /** 720 * @brief write silence events to the stream ringbuffers. 721 */ 722 bool StreamProcessor::provideSilenceBlock(unsigned int nevents, unsigned int offset) 723 { 724 bool no_problem=true; 725 for ( PortVectorIterator it = m_PeriodPorts.begin(); 726 it != m_PeriodPorts.end(); 727 ++it ) { 728 if((*it)->isDisabled()) {continue;}; 729 730 //FIXME: make this into a static_cast when not DEBUG? 731 Port *port=dynamic_cast<Port *>(*it); 732 733 switch(port->getPortType()) { 734 735 case Port::E_Audio: 736 if(provideSilenceToPort(static_cast<AudioPort *>(*it), offset, nevents)) { 737 debugWarning("Could not put silence into to port %s",(*it)->getName().c_str()); 738 no_problem=false; 739 } 740 break; 741 // midi is a packet based port, don't process 742 // case MotuPortInfo::E_Midi: 743 // break; 744 745 default: // ignore 746 break; 747 } 748 } 749 return no_problem; 750 } 751 752 int 753 StreamProcessor::provideSilenceToPort( 754 AudioPort *p, unsigned int offset, unsigned int nevents) 755 { 756 unsigned int j=0; 757 switch(p->getDataType()) { 758 default: 759 case Port::E_Int24: 760 { 761 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); 762 assert(nevents + offset <= p->getBufferSize()); 763 buffer+=offset; 764 765 for(j = 0; j < nevents; j += 1) { // decode max nsamples 766 *(buffer)=0; 767 buffer++; 768 } 769 } 770 break; 771 case Port::E_Float: 772 { 773 float *buffer=(float *)(p->getBufferAddress()); 774 assert(nevents + offset <= p->getBufferSize()); 775 buffer+=offset; 776 777 for(j = 0; j < nevents; j += 1) { // decode max nsamples 778 *buffer = 0.0; 779 buffer++; 780 } 781 } 782 break; 783 } 784 return 0; 707 785 } 708 786 branches/ppalmers-streaming/src/libstreaming/generic/StreamProcessor.h
r729 r733 210 210 virtual bool processReadBlock(char *data, unsigned int nevents, unsigned int offset) 211 211 {debugWarning("call not allowed\n"); return false;}; 212 virtual bool provideSilenceBlock(unsigned int nevents, unsigned int offset)213 {debugWarning("call not allowed\n"); return false;};214 212 215 213 // the following methods are to be implemented by transmit SP subclasses … … 238 236 virtual bool transmitSilenceBlock(char *data, unsigned int nevents, unsigned int offset) 239 237 {debugWarning("call not allowed\n"); return false;}; 238 protected: // some generic helpers 239 int provideSilenceToPort(AudioPort *p, unsigned int offset, unsigned int nevents); 240 bool provideSilenceBlock(unsigned int nevents, unsigned int offset); 240 241 241 242 private: … … 392 393 /** 393 394 * @brief get the nominal number of frames in a packet 395 * 396 * This is the amount of frames that is nominally present 397 * in one packet. It is recommended that in the receive handler 398 * you write this amount of frames when a valid packet has 399 * been received. (although this is not mandatory) 400 * 394 401 * @return the nominal number of frames in a packet 395 402 */ … … 400 407 * @return the nominal number of packet necessary 401 408 */ 402 virtual unsigned int getNominalPacketsNeeded(unsigned int nframes) = 0; 409 virtual unsigned int getNominalPacketsNeeded(unsigned int nframes); 410 411 /** 412 * @brief returns the actual frame rate as calculated by the SP's DLL 413 * @return the actual frame rate as detected by the DLL 414 */ 415 float getActualRate() 416 {return m_data_buffer->getRate();}; 403 417 404 418 protected: branches/ppalmers-streaming/src/libstreaming/motu/MotuReceiveStreamProcessor.cpp
r732 r733 22 22 */ 23 23 24 #include " AmdtpReceiveStreamProcessor.h"25 #include " AmdtpPort.h"24 #include "MotuReceiveStreamProcessor.h" 25 #include "MotuPort.h" 26 26 #include "../StreamProcessorManager.h" 27 27 28 28 #include "../util/cycletimer.h" 29 29 30 #include <math.h> 30 31 #include <netinet/in.h> 31 32 #include <assert.h> 32 33 33 // in ticks34 // as per AMDTP2.1:35 // 354.17us + 125us @ 24.576ticks/usec = 11776.08192 ticks36 #define DEFAULT_TRANSFER_DELAY (11776U)37 38 #define TRANSMIT_TRANSFER_DELAY DEFAULT_TRANSFER_DELAY39 40 34 namespace Streaming { 41 35 42 /* --------------------- RECEIVE ----------------------- */ 43 44 AmdtpReceiveStreamProcessor::AmdtpReceiveStreamProcessor(int port, int dimension) 36 // A macro to extract specific bits from a native endian quadlet 37 #define get_bits(_d,_start,_len) (((_d)>>((_start)-(_len)+1)) & ((1<<(_len))-1)) 38 39 // Convert an SPH timestamp as received from the MOTU to a full timestamp in ticks. 40 static inline uint32_t sphRecvToFullTicks(uint32_t sph, uint32_t ct_now) { 41 42 uint32_t timestamp = CYCLE_TIMER_TO_TICKS(sph & 0x1ffffff); 43 uint32_t now_cycles = CYCLE_TIMER_GET_CYCLES(ct_now); 44 45 uint32_t ts_sec = CYCLE_TIMER_GET_SECS(ct_now); 46 // If the cycles have wrapped, correct ts_sec so it represents when timestamp 47 // was received. The timestamps sent by the MOTU are always 1 or two cycles 48 // in advance of the cycle timer (reasons unknown at this stage). In addition, 49 // iso buffering can delay the arrival of packets for quite a number of cycles 50 // (have seen a delay >12 cycles). 51 // Every so often we also see sph wrapping ahead of ct_now, so deal with that 52 // too. 53 if (CYCLE_TIMER_GET_CYCLES(sph) > now_cycles + 1000) { 54 if (ts_sec) 55 ts_sec--; 56 else 57 ts_sec = 127; 58 } else 59 if (now_cycles > CYCLE_TIMER_GET_CYCLES(sph) + 1000) { 60 if (ts_sec == 127) 61 ts_sec = 0; 62 else 63 ts_sec++; 64 } 65 return timestamp + ts_sec*TICKS_PER_SECOND; 66 } 67 68 MotuReceiveStreamProcessor::MotuReceiveStreamProcessor(int port, unsigned int event_size) 45 69 : StreamProcessor(ePT_Receive , port) 46 , m_ dimension( dimension)70 , m_event_size(event_size) 47 71 {} 48 72 49 73 unsigned int 50 AmdtpReceiveStreamProcessor::getNominalPacketsNeeded(unsigned int nframes) 51 { 52 unsigned int nominal_frames_per_second = m_manager->getNominalRate(); 53 uint64_t nominal_ticks_per_frame = TICKS_PER_SECOND / nominal_frames_per_second; 54 uint64_t nominal_ticks = nominal_ticks_per_frame * nframes; 55 uint64_t nominal_packets = nominal_ticks / TICKS_PER_CYCLE; 56 return nominal_packets; 74 MotuReceiveStreamProcessor::getMaxPacketSize() { 75 int framerate = m_manager->getNominalRate(); 76 return framerate<=48000?616:(framerate<=96000?1032:1160); 57 77 } 58 78 59 79 unsigned int 60 AmdtpReceiveStreamProcessor::getPacketsPerPeriod() 61 { 62 return getNominalPacketsNeeded(m_manager->getPeriodSize()); 63 } 64 65 bool AmdtpReceiveStreamProcessor::prepareChild() { 80 MotuReceiveStreamProcessor::getNominalFramesPerPacket() { 81 int framerate = m_manager->getNominalRate(); 82 return framerate<=48000?8:(framerate<=96000?16:32); 83 } 84 85 bool 86 MotuReceiveStreamProcessor::prepareChild() { 66 87 debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this); 67 88 68 switch (m_manager->getNominalRate()) { 69 case 32000: 70 case 44100: 71 case 48000: 72 m_syt_interval = 8; 73 break; 74 case 88200: 75 case 96000: 76 m_syt_interval = 16; 77 break; 78 case 176400: 79 case 192000: 80 m_syt_interval = 32; 81 break; 82 default: 83 debugError("Unsupported rate: %d\n", m_manager->getNominalRate()); 84 return false; 85 } 89 // prepare the framerate estimate 90 // FIXME: not needed anymore? 91 //m_ticks_per_frame = (TICKS_PER_SECOND*1.0) / ((float)m_manager->getNominalRate()); 86 92 87 93 debugOutput( DEBUG_LEVEL_VERBOSE, "Prepared for:\n"); 88 debugOutput( DEBUG_LEVEL_VERBOSE, " Samplerate: %d , DBS: %d, SYT: %d\n",89 m_manager->getNominalRate() , m_dimension, m_syt_interval);94 debugOutput( DEBUG_LEVEL_VERBOSE, " Samplerate: %d\n", 95 m_manager->getNominalRate()); 90 96 debugOutput( DEBUG_LEVEL_VERBOSE, " PeriodSize: %d, NbBuffers: %d\n", 91 97 m_manager->getPeriodSize(), m_manager->getNbBuffers()); 92 98 debugOutput( DEBUG_LEVEL_VERBOSE, " Port: %d, Channel: %d\n", 93 m_port, m_channel);99 m_port, m_channel); 94 100 95 101 return true; … … 98 104 99 105 /** 100 * Processes packet header to extract timestamps and so on106 * Processes packet header to extract timestamps and check if the packet is valid 101 107 * @param data 102 108 * @param length … … 109 115 */ 110 116 enum StreamProcessor::eChildReturnValue 111 AmdtpReceiveStreamProcessor::processPacketHeader(unsigned char *data, unsigned int length,117 MotuReceiveStreamProcessor::processPacketHeader(unsigned char *data, unsigned int length, 112 118 unsigned char channel, unsigned char tag, unsigned char sy, 113 119 unsigned int cycle, unsigned int dropped) 114 120 { 115 struct iec61883_packet *packet = (struct iec61883_packet *) data; 116 assert(packet); 117 bool ok = (packet->syt != 0xFFFF) && 118 (packet->fdf != 0xFF) && 119 (packet->fmt == 0x10) && 120 (packet->dbs > 0) && 121 (length >= 2*sizeof(quadlet_t)); 122 if(ok) { 123 uint64_t now = m_handler->getCycleTimer(); 124 //=> convert the SYT to a full timestamp in ticks 125 m_last_timestamp = sytRecvToFullTicks((uint32_t)ntohs(packet->syt), 126 cycle, now); 127 } 128 return (ok ? eCRV_OK : eCRV_Invalid ); 121 if (length > 8) { 122 // The iso data blocks from the MOTUs comprise a CIP-like 123 // header followed by a number of events (8 for 1x rates, 16 124 // for 2x rates, 32 for 4x rates). 125 quadlet_t *quadlet = (quadlet_t *)data; 126 unsigned int dbs = get_bits(ntohl(quadlet[0]), 23, 8); // Size of one event in terms of fdf_size 127 unsigned int fdf_size = get_bits(ntohl(quadlet[1]), 23, 8) == 0x22 ? 32:0; // Event unit size in bits 128 129 // Don't even attempt to process a packet if it isn't what 130 // we expect from a MOTU. Yes, an FDF value of 32 bears 131 // little relationship to the actual data (24 bit integer) 132 // sent by the MOTU - it's one of those areas where MOTU 133 // have taken a curious detour around the standards. 134 if (tag!=1 || fdf_size!=32) { 135 return eCRV_Invalid; 136 } 137 138 // put this after the check because event_length can become 0 on invalid packets 139 unsigned int event_length = (fdf_size * dbs) / 8; // Event size in bytes 140 unsigned int n_events = (length-8) / event_length; 141 142 // Acquire the timestamp of the last frame in the packet just 143 // received. Since every frame from the MOTU has its own timestamp 144 // we can just pick it straight from the packet. 145 uint32_t last_sph = ntohl(*(quadlet_t *)(data+8+(n_events-1)*event_length)); 146 m_last_timestamp = sphRecvToFullTicks(last_sph, m_handler->getCycleTimer()); 147 return eCRV_OK; 148 } else { 149 return eCRV_Invalid; 150 } 129 151 } 130 152 … … 142 164 */ 143 165 enum StreamProcessor::eChildReturnValue 144 AmdtpReceiveStreamProcessor::processPacketData(unsigned char *data, unsigned int length,166 MotuReceiveStreamProcessor::processPacketData(unsigned char *data, unsigned int length, 145 167 unsigned char channel, unsigned char tag, unsigned char sy, 146 168 unsigned int cycle, unsigned int dropped_cycles) { 147 struct iec61883_packet *packet = (struct iec61883_packet *) data; 148 assert(packet); 149 150 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs; 169 quadlet_t* quadlet = (quadlet_t*) data; 170 171 unsigned int dbs = get_bits(ntohl(quadlet[0]), 23, 8); // Size of one event in terms of fdf_size 172 unsigned int fdf_size = get_bits(ntohl(quadlet[1]), 23, 8) == 0x22 ? 32:0; // Event unit size in bits 173 // this is only called for packets that return eCRV_OK on processPacketHeader 174 // so event_length won't become 0 175 unsigned int event_length = (fdf_size * dbs) / 8; // Event size in bytes 176 unsigned int n_events = (length-8) / event_length; 151 177 152 178 // we have to keep in mind that there are also … … 159 185 #ifdef DEBUG 160 186 if(isRunning()) { 161 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"STMP: %lluticks | buff=%d, syt_interval=%d,tpf=%f\n",162 m_last_timestamp, m_handler->getWakeupInterval(), m_syt_interval,getTicksPerFrame());187 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"STMP: %lluticks | buff=%d, tpf=%f\n", 188 m_last_timestamp, m_handler->getWakeupInterval(), getTicksPerFrame()); 163 189 } 164 190 #endif 165 191 166 if(m_data_buffer->writeFrames(nevents, (char *)(data+8), m_last_timestamp)) { 192 if(m_data_buffer->writeFrames(n_events, (char *)(data+8), m_last_timestamp)) { 193 int dbc = get_bits(ntohl(quadlet[0]), 8, 8); 167 194 // process all ports that should be handled on a per-packet base 168 195 // this is MIDI for AMDTP (due to the need of DBC) 169 196 if(isRunning()) { 170 if (!decodePacketPorts((quadlet_t *)(data+8), n events, packet->dbc)) {197 if (!decodePacketPorts((quadlet_t *)(data+8), n_events, dbc)) { 171 198 debugWarning("Problem decoding Packet Ports\n"); 172 199 } … … 182 209 ***********************************************/ 183 210 /** 184 * @brief write received events to the streamringbuffers.185 */ 186 bool AmdtpReceiveStreamProcessor::processReadBlock(char *data,211 * \brief write received events to the port ringbuffers. 212 */ 213 bool MotuReceiveStreamProcessor::processReadBlock(char *data, 187 214 unsigned int nevents, unsigned int offset) 188 215 { 189 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "(%p)->processReadBlock(%u, %u)\n",this,nevents,offset);190 191 216 bool no_problem=true; 192 193 217 for ( PortVectorIterator it = m_PeriodPorts.begin(); 194 218 it != m_PeriodPorts.end(); 195 ++it ) 196 { 219 ++it ) { 197 220 if((*it)->isDisabled()) {continue;}; 198 221 199 222 //FIXME: make this into a static_cast when not DEBUG? 200 201 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it); 202 assert(pinfo); // this should not fail!! 203 204 switch(pinfo->getFormat()) { 205 case AmdtpPortInfo::E_MBLA: 206 if(decodeMBLAEventsToPort(static_cast<AmdtpAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) { 207 debugWarning("Could not decode packet MBLA to port %s",(*it)->getName().c_str()); 223 Port *port=dynamic_cast<Port *>(*it); 224 225 switch(port->getPortType()) { 226 227 case Port::E_Audio: 228 if(decodeMotuEventsToPort(static_cast<MotuAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) { 229 debugWarning("Could not decode packet data to port %s",(*it)->getName().c_str()); 208 230 no_problem=false; 209 231 } 210 232 break; 211 case AmdtpPortInfo::E_SPDIF: // still unimplemented 212 break; 213 /* for this processor, midi is a packet based port 214 case AmdtpPortInfo::E_Midi: 215 break;*/ 216 default: // ignore 217 break; 218 } 219 } 220 return no_problem; 221 } 222 223 /** 224 * @brief write silence events to the stream ringbuffers. 225 */ 226 bool AmdtpReceiveStreamProcessor::provideSilenceBlock(unsigned int nevents, unsigned int offset) 227 { 228 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "(%p)->proviceSilenceBlock(%u, %u)\n", this, nevents, offset); 229 230 bool no_problem=true; 231 232 for ( PortVectorIterator it = m_PeriodPorts.begin(); 233 it != m_PeriodPorts.end(); 234 ++it ) 235 { 236 if((*it)->isDisabled()) {continue;}; 237 //FIXME: make this into a static_cast when not DEBUG? 238 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it); 239 assert(pinfo); // this should not fail!! 240 241 switch(pinfo->getFormat()) { 242 case AmdtpPortInfo::E_MBLA: 243 if(provideSilenceToPort(static_cast<AmdtpAudioPort *>(*it), offset, nevents)) { 244 debugWarning("Could not put silence into to port %s",(*it)->getName().c_str()); 245 no_problem=false; 246 } 247 break; 248 case AmdtpPortInfo::E_SPDIF: // still unimplemented 249 break; 250 /* for this processor, midi is a packet based port 251 case AmdtpPortInfo::E_Midi: 252 break;*/ 233 // midi is a packet based port, don't process 234 // case MotuPortInfo::E_Midi: 235 // break; 236 253 237 default: // ignore 254 238 break; … … 266 250 * @return true if all successfull 267 251 */ 268 bool AmdtpReceiveStreamProcessor::decodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc)269 {252 bool MotuReceiveStreamProcessor::decodePacketPorts(quadlet_t *data, unsigned int nevents, 253 unsigned int dbc) { 270 254 bool ok=true; 271 255 272 quadlet_t *target_event=NULL; 273 unsigned int j; 256 // Use char here since the source address won't necessarily be 257 // aligned; use of an unaligned quadlet_t may cause issues on 258 // certain architectures. Besides, the source for MIDI data going 259 // directly to the MOTU isn't structured in quadlets anyway; it is a 260 // sequence of 3 unaligned bytes. 261 unsigned char *src = NULL; 274 262 275 263 for ( PortVectorIterator it = m_PacketPorts.begin(); 276 it != m_PacketPorts.end(); 277 ++it ) 278 { 279 280 #ifdef DEBUG 281 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it); 282 assert(pinfo); // this should not fail!! 283 284 // the only packet type of events for AMDTP is MIDI in mbla 285 assert(pinfo->getFormat()==AmdtpPortInfo::E_Midi); 286 #endif 287 AmdtpMidiPort *mp=static_cast<AmdtpMidiPort *>(*it); 288 289 // we decode this directly (no function call) due to the high frequency 290 /* idea: 291 spec says: current_midi_port=(dbc+j)%8; 292 => if we start at (dbc+stream->location-1)%8, 293 we'll start at the right event for the midi port. 294 => if we increment j with 8, we stay at the right event. 295 */ 296 // FIXME: as we know in advance how big a packet is (syt_interval) we can 297 // predict how much loops will be present here 298 for(j = (dbc & 0x07)+mp->getLocation(); j < nevents; j += 8) { 299 target_event=(quadlet_t *)(data + ((j * m_dimension) + mp->getPosition())); 300 quadlet_t sample_int=ntohl(*target_event); 301 // FIXME: this assumes that 2X and 3X speed isn't used, 302 // because only the 1X slot is put into the ringbuffer 303 if(IEC61883_AM824_GET_LABEL(sample_int) != IEC61883_AM824_LABEL_MIDI_NO_DATA) { 304 sample_int=(sample_int >> 16) & 0x000000FF; 305 if(!mp->writeEvent(&sample_int)) { 306 debugWarning("Packet port events lost\n"); 307 ok=false; 264 it != m_PacketPorts.end(); 265 ++it ) { 266 267 Port *port=dynamic_cast<Port *>(*it); 268 assert(port); // this should not fail!! 269 270 // Currently the only packet type of events for MOTU 271 // is MIDI in mbla. However in future control data 272 // might also be sent via "packet" events, so allow 273 // for this possible expansion. 274 275 // FIXME: MIDI input is completely untested at present. 276 switch (port->getPortType()) { 277 case Port::E_Midi: { 278 MotuMidiPort *mp=static_cast<MotuMidiPort *>(*it); 279 signed int sample; 280 unsigned int j = 0; 281 // Get MIDI bytes if present anywhere in the 282 // packet. MOTU MIDI data is sent using a 283 // 3-byte sequence starting at the port's 284 // position. It's thought that there can never 285 // be more than one MIDI byte per packet, but 286 // for completeness we'll check the entire packet 287 // anyway. 288 src = (unsigned char *)data + mp->getPosition(); 289 while (j < nevents) { 290 if (*src==0x01 && *(src+1)==0x00) { 291 sample = *(src+2); 292 if (!mp->writeEvent(&sample)) { 293 debugWarning("MIDI packet port events lost\n"); 294 ok = false; 295 } 296 } 297 j++; 298 src += m_event_size; 308 299 } 309 } 310 } 311 300 break; 301 } 302 default: 303 debugOutput(DEBUG_LEVEL_VERBOSE, "Unknown packet-type port format %d\n",port->getPortType()); 304 return ok; 305 } 312 306 } 313 307 … … 315 309 } 316 310 317 int 318 AmdtpReceiveStreamProcessor::decodeMBLAEventsToPort( 319 AmdtpAudioPort *p, quadlet_t *data, 320 unsigned int offset, unsigned int nevents) 311 signed int MotuReceiveStreamProcessor::decodeMotuEventsToPort(MotuAudioPort *p, 312 quadlet_t *data, unsigned int offset, unsigned int nevents) 321 313 { 322 314 unsigned int j=0; 323 quadlet_t *target_event; 324 325 target_event=(quadlet_t *)(data + p->getPosition()); 315 316 // Use char here since a port's source address won't necessarily be 317 // aligned; use of an unaligned quadlet_t may cause issues on 318 // certain architectures. Besides, the source (data coming directly 319 // from the MOTU) isn't structured in quadlets anyway; it mainly 320 // consists of packed 24-bit integers. 321 322 unsigned char *src_data; 323 src_data = (unsigned char *)data + p->getPosition(); 326 324 327 325 switch(p->getDataType()) { … … 333 331 assert(nevents + offset <= p->getBufferSize()); 334 332 333 // Offset is in frames, but each port is only a single 334 // channel, so the number of frames is the same as the 335 // number of quadlets to offset (assuming the port buffer 336 // uses one quadlet per sample, which is the case currently). 335 337 buffer+=offset; 336 338 337 for(j = 0; j < nevents; j += 1) { // decode max nsamples 338 *(buffer)=(ntohl((*target_event) ) & 0x00FFFFFF); 339 for(j = 0; j < nevents; j += 1) { // Decode nsamples 340 *buffer = (*src_data<<16)+(*(src_data+1)<<8)+*(src_data+2); 341 // Sign-extend highest bit of 24-bit int. 342 // FIXME: this isn't strictly needed since E_Int24 is a 24-bit, 343 // but doing so shouldn't break anything and makes the data 344 // easier to deal with during debugging. 345 if (*src_data & 0x80) 346 *buffer |= 0xff000000; 347 339 348 buffer++; 340 target_event+=m_dimension;349 src_data+=m_event_size; 341 350 } 342 351 } … … 353 362 for(j = 0; j < nevents; j += 1) { // decode max nsamples 354 363 355 unsigned int v = ntohl(*target_event) & 0x00FFFFFF; 364 unsigned int v = (*src_data<<16)+(*(src_data+1)<<8)+*(src_data+2); 365 356 366 // sign-extend highest bit of 24-bit int 357 367 int tmp = (int)(v << 8) / 256; … … 360 370 361 371 buffer++; 362 target_event+=m_dimension;372 src_data+=m_event_size; 363 373 } 364 374 } … … 369 379 } 370 380 371 int372 AmdtpReceiveStreamProcessor::provideSilenceToPort(373 AmdtpAudioPort *p, unsigned int offset, unsigned int nevents)374 {375 unsigned int j=0;376 switch(p->getDataType()) {377 default:378 case Port::E_Int24:379 {380 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());381 assert(nevents + offset <= p->getBufferSize());382 buffer+=offset;383 384 for(j = 0; j < nevents; j += 1) { // decode max nsamples385 *(buffer)=0;386 buffer++;387 }388 }389 break;390 case Port::E_Float:391 {392 float *buffer=(float *)(p->getBufferAddress());393 assert(nevents + offset <= p->getBufferSize());394 buffer+=offset;395 396 for(j = 0; j < nevents; j += 1) { // decode max nsamples397 *buffer = 0.0;398 buffer++;399 }400 }401 break;402 }403 return 0;404 }405 406 381 } // end of namespace Streaming branches/ppalmers-streaming/src/libstreaming/motu/MotuReceiveStreamProcessor.h
r732 r733 22 22 */ 23 23 24 #ifndef __FFADO_ AMDTPRECEIVESTREAMPROCESSOR__25 #define __FFADO_ AMDTPRECEIVESTREAMPROCESSOR__24 #ifndef __FFADO_MOTURECEIVESTREAMPROCESSOR__ 25 #define __FFADO_MOTURECEIVESTREAMPROCESSOR__ 26 26 27 27 /** 28 * This class implements IEC61883-6 / AM824 / AMDTP basedstreaming28 * This class implements MOTU streaming 29 29 */ 30 30 … … 34 34 #include "../util/cip.h" 35 35 36 #include <libiec61883/iec61883.h>37 #include <pthread.h>38 39 #define AMDTP_MAX_PACKET_SIZE 204840 41 #define IEC61883_STREAM_TYPE_MIDI 0x0D42 #define IEC61883_STREAM_TYPE_SPDIF 0x0043 #define IEC61883_STREAM_TYPE_MBLA 0x0644 45 #define IEC61883_AM824_LABEL_MASK 0xFF00000046 #define IEC61883_AM824_GET_LABEL(x) (((x) & 0xFF000000) >> 24)47 #define IEC61883_AM824_SET_LABEL(x,y) ((x) | ((y)<<24))48 49 #define IEC61883_AM824_LABEL_MIDI_NO_DATA 0x8050 #define IEC61883_AM824_LABEL_MIDI_1X 0x8151 #define IEC61883_AM824_LABEL_MIDI_2X 0x8252 #define IEC61883_AM824_LABEL_MIDI_3X 0x8353 54 36 namespace Streaming { 55 37 56 class Port; 57 class AmdtpAudioPort; 58 class AmdtpMidiPort; 38 class MotuAudioPort; 59 39 /*! 60 \brief The Base Class for an AMDTPreceive stream processor61 62 This class implements a ReceiveStreamProcessor that demultiplexes63 AMDTP streams into Ports.64 65 */66 class AmdtpReceiveStreamProcessor40 * \brief The Base Class for a MOTU receive stream processor 41 * 42 * This class implements the outgoing stream processing for 43 * motu devices 44 * 45 */ 46 class MotuReceiveStreamProcessor 67 47 : public StreamProcessor 68 48 { … … 70 50 public: 71 51 /** 72 * Create a AMDTPreceive StreamProcessor52 * Create a MOTU receive StreamProcessor 73 53 * @param port 1394 port 74 54 * @param dimension number of substreams in the ISO stream 75 55 * (midi-muxed is only one stream) 76 56 */ 77 AmdtpReceiveStreamProcessor(int port, int dimension);78 virtual ~ AmdtpReceiveStreamProcessor() {};57 MotuReceiveStreamProcessor(int port, unsigned int event_size); 58 virtual ~MotuReceiveStreamProcessor() {}; 79 59 80 60 enum eChildReturnValue processPacketHeader(unsigned char *data, unsigned int length, … … 89 69 public: 90 70 virtual unsigned int getEventSize() 91 {return 4;}; 92 virtual unsigned int getMaxPacketSize() 93 {return 4 * (2 + m_syt_interval * m_dimension);}; 71 {return m_event_size;}; 72 virtual unsigned int getMaxPacketSize(); 94 73 virtual unsigned int getEventsPerFrame() 95 { return m_dimension; }; 96 virtual unsigned int getNominalFramesPerPacket() 97 {return m_syt_interval;}; 98 virtual unsigned int getPacketsPerPeriod(); 99 virtual unsigned int getNominalPacketsNeeded(unsigned int nframes); 74 { return 1; }; // FIXME: check 75 virtual unsigned int getNominalFramesPerPacket(); 100 76 101 77 protected: 102 78 bool processReadBlock(char *data, unsigned int nevents, unsigned int offset); 103 bool provideSilenceBlock(unsigned int nevents, unsigned int offset);104 79 105 80 private: 106 81 bool decodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc); 107 82 108 int decodeMBLAEventsToPort(AmdtpAudioPort *, quadlet_t *data, unsigned int offset, unsigned int nevents); 109 int provideSilenceToPort(AmdtpAudioPort *p, unsigned int offset, unsigned int nevents); 83 int decodeMotuEventsToPort(MotuAudioPort *, quadlet_t *data, unsigned int offset, unsigned int nevents); 110 84 111 int m_dimension;112 unsigned int m_syt_interval;113 114 uint64_t m_last_syt; /// FIXME:debug115 u int64_t m_last_now; /// FIXME:debug85 /* 86 * An iso packet mostly consists of multiple events. m_event_size 87 * is the size of a single 'event' in bytes. 88 */ 89 unsigned int m_event_size; 116 90 }; 117 91 … … 119 93 } // end of namespace Streaming 120 94 121 #endif /* __FFADO_ AMDTPRECEIVESTREAMPROCESSOR__ */95 #endif /* __FFADO_MOTURECEIVESTREAMPROCESSOR__ */ 122 96 branches/ppalmers-streaming/src/libstreaming/motu/MotuTransmitStreamProcessor.cpp
r732 r733 22 22 */ 23 23 24 #include " AmdtpTransmitStreamProcessor.h"25 #include " AmdtpPort.h"24 #include "MotuTransmitStreamProcessor.h" 25 #include "MotuPort.h" 26 26 #include "../StreamProcessorManager.h" 27 27 … … 41 41 { 42 42 43 // A macro to extract specific bits from a native endian quadlet 44 #define get_bits(_d,_start,_len) (((_d)>>((_start)-(_len)+1)) & ((1<<(_len))-1)) 45 46 // Convert a full timestamp into an SPH timestamp as required by the MOTU 47 static inline uint32_t fullTicksToSph(int64_t timestamp) { 48 return TICKS_TO_CYCLE_TIMER(timestamp) & 0x1ffffff; 49 } 50 43 51 /* transmit */ 44 AmdtpTransmitStreamProcessor::AmdtpTransmitStreamProcessor ( int port, int dimension)52 MotuTransmitStreamProcessor::MotuTransmitStreamProcessor ( int port, unsigned int event_size ) 45 53 : StreamProcessor ( ePT_Transmit, port ) 46 , m_ dimension ( dimension)47 , m_ dbc ( 0 )54 , m_event_size ( event_size ) 55 , m_tx_dbc ( 0 ) 48 56 {} 49 57 58 59 unsigned int 60 MotuTransmitStreamProcessor::getMaxPacketSize() { 61 int framerate = m_manager->getNominalRate(); 62 return framerate<=48000?616:(framerate<=96000?1032:1160); 63 } 64 65 unsigned int 66 MotuTransmitStreamProcessor::getNominalFramesPerPacket() { 67 int framerate = m_manager->getNominalRate(); 68 return framerate<=48000?8:(framerate<=96000?16:32); 69 } 70 50 71 enum StreamProcessor::eChildReturnValue 51 AmdtpTransmitStreamProcessor::generatePacketHeader (72 MotuTransmitStreamProcessor::generatePacketHeader ( 52 73 unsigned char *data, unsigned int *length, 53 74 unsigned char *tag, unsigned char *sy, 54 75 int cycle, unsigned int dropped, unsigned int max_length ) 55 76 { 56 struct iec61883_packet *packet = ( struct iec61883_packet * ) data; 57 /* Our node ID can change after a bus reset, so it is best to fetch 58 * our node ID for each packet. */ 59 packet->sid = m_handler->getLocalNodeId() & 0x3f; 60 61 packet->dbs = m_dimension; 62 packet->fn = 0; 63 packet->qpc = 0; 64 packet->sph = 0; 65 packet->reserved = 0; 66 packet->dbc = m_dbc; 67 packet->eoh1 = 2; 68 packet->fmt = IEC61883_FMT_AMDTP; 69 70 *tag = IEC61883_TAG_WITH_CIP; 71 *sy = 0; 77 // The number of events per packet expected by the MOTU is solely 78 // dependent on the current sample rate. An 'event' is one sample from 79 // all channels plus possibly other midi and control data. 80 signed n_events = getNominalFramesPerPacket(); 81 82 // Do housekeeping expected for all packets sent to the MOTU, even 83 // for packets containing no audio data. 84 *sy = 0x00; 85 *tag = 1; // All MOTU packets have a CIP-like header 86 *length = n_events*m_event_size + 8; 72 87 73 88 signed int fc; … … 143 158 // 2) there are enough packets 144 159 // => determine whether we have to send them in this packet 145 if ( fc < ( signed int ) m_syt_interval)160 if ( fc < ( signed int ) getNominalFramesPerPacket() ) 146 161 { 147 162 // not enough frames in the buffer, … … 201 216 { 202 217 // we are not that late and can still try to transmit the packet 203 m_dbc += fillDataPacketHeader(packet, length, m_last_timestamp); 218 m_tx_dbc += fillDataPacketHeader((quadlet_t *)data, length, m_last_timestamp); 219 if (m_tx_dbc > 0xff) 220 m_tx_dbc -= 0x100; 204 221 return eCRV_Packet; 205 222 } … … 212 229 { 213 230 // it's time send the packet 214 m_dbc += fillDataPacketHeader(packet, length, m_last_timestamp); 231 m_tx_dbc += fillDataPacketHeader((quadlet_t *)data, length, m_last_timestamp); 232 if (m_tx_dbc > 0xff) 233 m_tx_dbc -= 0x100; 215 234 return eCRV_Packet; 216 235 } … … 242 261 243 262 enum StreamProcessor::eChildReturnValue 244 AmdtpTransmitStreamProcessor::generatePacketData (263 MotuTransmitStreamProcessor::generatePacketData ( 245 264 unsigned char *data, unsigned int *length, 246 265 unsigned char *tag, unsigned char *sy, 247 266 int cycle, unsigned int dropped, unsigned int max_length ) 248 267 { 249 struct iec61883_packet *packet = ( struct iec61883_packet * ) data; 250 if ( m_data_buffer->readFrames ( m_syt_interval, ( char * ) ( data + 8 ) ) ) 251 { 252 // process all ports that should be handled on a per-packet base 253 // this is MIDI for AMDTP (due to the need of DBC) 254 if ( !encodePacketPorts ( ( quadlet_t * ) ( data+8 ), m_syt_interval, packet->dbc ) ) 255 { 256 debugWarning ( "Problem encoding Packet Ports\n" ); 257 } 258 debugOutput ( DEBUG_LEVEL_VERY_VERBOSE, "XMIT DATA: TSP=%011llu (%04u)\n", 259 cycle, m_last_timestamp, ( unsigned int ) TICKS_TO_CYCLES ( m_last_timestamp ) ); 268 quadlet_t *quadlet = (quadlet_t *)data; 269 quadlet += 2; // skip the header 270 // Size of a single data frame in quadlets 271 unsigned dbs = m_event_size / 4; 272 273 // The number of events per packet expected by the MOTU is solely 274 // dependent on the current sample rate. An 'event' is one sample from 275 // all channels plus possibly other midi and control data. 276 signed n_events = getNominalFramesPerPacket(); 277 278 if (m_data_buffer->readFrames(n_events, (char *)(data + 8))) { 279 float ticks_per_frame = m_manager->getSyncSource().getActualRate(); 280 281 #if TESTTONE 282 // FIXME: remove this hacked in 1 kHz test signal to 283 // analog-1 when testing is complete. 284 signed int int_tpf = (int)ticks_per_frame; 285 unsigned char *sample = data+8+16; 286 for (i=0; i<n_events; i++, sample+=m_event_size) { 287 static signed int a_cx = 0; 288 // Each sample is 3 bytes with MSB in lowest address (ie: 289 // network byte order). After byte order swap, the 24-bit 290 // MSB is in the second byte of val. 291 signed int val = htonl((int)(0x7fffff*sin((1000.0*2.0*M_PI/24576000.0)*a_cx))); 292 memcpy(sample,((char *)&val)+1,3); 293 if ((a_cx+=int_tpf) >= 24576000) { 294 a_cx -= 24576000; 295 } 296 } 297 #endif 298 299 // Set up each frames's SPH. 300 for (unsigned int i=0; i<n_events; i++, quadlet += dbs) { 301 //FIXME: not sure which is best for the MOTU 302 // int64_t ts_frame = addTicks(ts, (unsigned int)(i * ticks_per_frame)); 303 int64_t ts_frame = addTicks(m_last_timestamp, (unsigned int)(i * ticks_per_frame)); 304 *quadlet = htonl(fullTicksToSph(ts_frame)); 305 } 306 307 // Process all ports that should be handled on a per-packet base 308 // this is MIDI for AMDTP (due to the need of DBC, which is lost 309 // when putting the events in the ringbuffer) 310 // for motu this might also be control data, however as control 311 // data isn't time specific I would also include it in the period 312 // based processing 313 314 // FIXME: m_tx_dbc probably needs to be initialised to a non-zero 315 // value somehow so MIDI sync is possible. For now we ignore 316 // this issue. 317 if (!encodePacketPorts((quadlet_t *)(data+8), n_events, m_tx_dbc)) { 318 debugWarning("Problem encoding Packet Ports\n"); 319 } 320 260 321 return eCRV_OK; 261 322 } … … 265 326 266 327 enum StreamProcessor::eChildReturnValue 267 AmdtpTransmitStreamProcessor::generateSilentPacketHeader (328 MotuTransmitStreamProcessor::generateSilentPacketHeader ( 268 329 unsigned char *data, unsigned int *length, 269 330 unsigned char *tag, unsigned char *sy, 270 331 int cycle, unsigned int dropped, unsigned int max_length ) 271 332 { 272 struct iec61883_packet *packet = ( struct iec61883_packet * ) data;273 333 debugOutput ( DEBUG_LEVEL_VERY_VERBOSE, "XMIT NONE: CY=%04u, TSP=%011llu (%04u)\n", 274 334 cycle, m_last_timestamp, ( unsigned int ) TICKS_TO_CYCLES ( m_last_timestamp ) ); 275 335 276 /* Our node ID can change after a bus reset, so it is best to fetch 277 * our node ID for each packet. */ 278 packet->sid = m_handler->getLocalNodeId() & 0x3f; 279 280 packet->dbs = m_dimension; 281 packet->fn = 0; 282 packet->qpc = 0; 283 packet->sph = 0; 284 packet->reserved = 0; 285 packet->dbc = m_dbc; 286 packet->eoh1 = 2; 287 packet->fmt = IEC61883_FMT_AMDTP; 288 289 *tag = IEC61883_TAG_WITH_CIP; 290 *sy = 0; 291 292 m_dbc += fillNoDataPacketHeader ( packet, length ); 336 // Do housekeeping expected for all packets sent to the MOTU, even 337 // for packets containing no audio data. 338 *sy = 0x00; 339 *tag = 1; // All MOTU packets have a CIP-like header 340 *length = 8; 341 342 m_tx_dbc += fillNoDataPacketHeader ( (quadlet_t *)data, length ); 293 343 return eCRV_OK; 294 344 } 295 345 296 346 enum StreamProcessor::eChildReturnValue 297 AmdtpTransmitStreamProcessor::generateSilentPacketData (347 MotuTransmitStreamProcessor::generateSilentPacketData ( 298 348 unsigned char *data, unsigned int *length, 299 349 unsigned char *tag, unsigned char *sy, … … 303 353 } 304 354 305 unsigned int AmdtpTransmitStreamProcessor::fillDataPacketHeader (306 struct iec61883_packet *packet, unsigned int* length,355 unsigned int MotuTransmitStreamProcessor::fillDataPacketHeader ( 356 quadlet_t *data, unsigned int* length, 307 357 uint32_t ts ) 308 358 { 309 310 packet->fdf = m_fdf; 311 312 // convert the timestamp to SYT format 313 uint16_t timestamp_SYT = TICKS_TO_SYT ( ts ); 314 packet->syt = ntohs ( timestamp_SYT ); 315 316 *length = m_syt_interval*sizeof ( quadlet_t ) *m_dimension + 8; 317 318 return m_syt_interval; 319 } 320 321 unsigned int AmdtpTransmitStreamProcessor::fillNoDataPacketHeader ( 322 struct iec61883_packet *packet, unsigned int* length ) 323 { 324 325 // no-data packets have syt=0xFFFF 326 // and have the usual amount of events as dummy data (?) 327 packet->fdf = IEC61883_FDF_NODATA; 328 packet->syt = 0xffff; 329 330 // FIXME: either make this a setting or choose 331 bool send_payload=true; 332 if ( send_payload ) 333 { 334 // this means no-data packets with payload (DICE doesn't like that) 335 *length = 2*sizeof ( quadlet_t ) + m_syt_interval * m_dimension * sizeof ( quadlet_t ); 336 return m_syt_interval; 337 } 338 else 339 { 340 // dbc is not incremented 341 // this means no-data packets without payload 342 *length = 2*sizeof ( quadlet_t ); 343 return 0; 344 } 345 } 346 347 unsigned int 348 AmdtpTransmitStreamProcessor::getNominalPacketsNeeded(unsigned int nframes) 349 { 350 unsigned int nominal_frames_per_second = m_manager->getNominalRate(); 351 uint64_t nominal_ticks_per_frame = TICKS_PER_SECOND / nominal_frames_per_second; 352 uint64_t nominal_ticks = nominal_ticks_per_frame * nframes; 353 uint64_t nominal_packets = nominal_ticks / TICKS_PER_CYCLE; 354 return nominal_packets; 355 } 356 357 unsigned int 358 AmdtpTransmitStreamProcessor::getPacketsPerPeriod() 359 { 360 return getNominalPacketsNeeded(m_manager->getPeriodSize()); 361 } 362 363 bool AmdtpTransmitStreamProcessor::prepareChild() 359 quadlet_t *quadlet = (quadlet_t *)data; 360 // Size of a single data frame in quadlets 361 unsigned dbs = m_event_size / 4; 362 363 // The number of events per packet expected by the MOTU is solely 364 // dependent on the current sample rate. An 'event' is one sample from 365 // all channels plus possibly other midi and control data. 366 signed n_events = getNominalFramesPerPacket(); 367 368 // construct the packet CIP-like header. Even if this is a data-less 369 // packet the dbs field is still set as if there were data blocks 370 // present. For data-less packets the dbc is the same as the previously 371 // transmitted block. 372 *quadlet = htonl(0x00000400 | ((m_handler->getLocalNodeId()&0x3f)<<24) | m_tx_dbc | (dbs<<16)); 373 quadlet++; 374 *quadlet = htonl(0x8222ffff); 375 quadlet++; 376 return n_events; 377 } 378 379 unsigned int MotuTransmitStreamProcessor::fillNoDataPacketHeader ( 380 quadlet_t *data, unsigned int* length ) 381 { 382 quadlet_t *quadlet = (quadlet_t *)data; 383 // Size of a single data frame in quadlets 384 unsigned dbs = m_event_size / 4; 385 // construct the packet CIP-like header. Even if this is a data-less 386 // packet the dbs field is still set as if there were data blocks 387 // present. For data-less packets the dbc is the same as the previously 388 // transmitted block. 389 *quadlet = htonl(0x00000400 | ((m_handler->getLocalNodeId()&0x3f)<<24) | m_tx_dbc | (dbs<<16)); 390 quadlet++; 391 *quadlet = htonl(0x8222ffff); 392 quadlet++; 393 *length = 8; 394 return 0; 395 } 396 397 bool MotuTransmitStreamProcessor::prepareChild() 364 398 { 365 399 debugOutput ( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this ); 366 switch ( m_manager->getNominalRate() ) 367 { 368 case 32000: 369 m_syt_interval = 8; 370 m_fdf = IEC61883_FDF_SFC_32KHZ; 371 break; 372 case 44100: 373 m_syt_interval = 8; 374 m_fdf = IEC61883_FDF_SFC_44K1HZ; 375 break; 376 default: 377 case 48000: 378 m_syt_interval = 8; 379 m_fdf = IEC61883_FDF_SFC_48KHZ; 380 break; 381 case 88200: 382 m_syt_interval = 16; 383 m_fdf = IEC61883_FDF_SFC_88K2HZ; 384 break; 385 case 96000: 386 m_syt_interval = 16; 387 m_fdf = IEC61883_FDF_SFC_96KHZ; 388 break; 389 case 176400: 390 m_syt_interval = 32; 391 m_fdf = IEC61883_FDF_SFC_176K4HZ; 392 break; 393 case 192000: 394 m_syt_interval = 32; 395 m_fdf = IEC61883_FDF_SFC_192KHZ; 396 break; 397 } 398 399 iec61883_cip_init ( 400 &m_cip_status, 401 IEC61883_FMT_AMDTP, 402 m_fdf, 403 m_manager->getNominalRate(), 404 m_dimension, 405 m_syt_interval ); 406 400 401 402 #if 0 407 403 for ( PortVectorIterator it = m_Ports.begin(); 408 404 it != m_Ports.end(); … … 431 427 } 432 428 } 429 #endif 433 430 434 431 debugOutput ( DEBUG_LEVEL_VERBOSE, "Prepared for:\n" ); 435 debugOutput ( DEBUG_LEVEL_VERBOSE, " Samplerate: %d , FDF: %d, DBS: %d, SYT: %d\n",436 m_manager->getNominalRate() , m_fdf, m_dimension, m_syt_interval);432 debugOutput ( DEBUG_LEVEL_VERBOSE, " Samplerate: %d\n", 433 m_manager->getNominalRate() ); 437 434 debugOutput ( DEBUG_LEVEL_VERBOSE, " PeriodSize: %d, NbBuffers: %d\n", 438 435 m_manager->getPeriodSize(), m_manager->getNbBuffers() ); 439 436 debugOutput ( DEBUG_LEVEL_VERBOSE, " Port: %d, Channel: %d\n", 440 m_port, m_channel );437 m_port, m_channel ); 441 438 return true; 442 439 } … … 445 442 * compose the event streams for the packets from the port buffers 446 443 */ 447 bool AmdtpTransmitStreamProcessor::processWriteBlock ( char *data, 448 unsigned int nevents, unsigned int offset ) 449 { 444 bool MotuTransmitStreamProcessor::processWriteBlock(char *data, 445 unsigned int nevents, unsigned int offset) { 446 bool no_problem=true; 447 unsigned int i; 448 449 // FIXME: ensure the MIDI and control streams are all zeroed until 450 // such time as they are fully implemented. 451 for (i=0; i<nevents; i++) { 452 memset(data+4+i*m_event_size, 0x00, 6); 453 } 454 455 for ( PortVectorIterator it = m_PeriodPorts.begin(); 456 it != m_PeriodPorts.end(); 457 ++it ) { 458 // If this port is disabled, don't process it 459 if((*it)->isDisabled()) {continue;}; 460 461 //FIXME: make this into a static_cast when not DEBUG? 462 Port *port=dynamic_cast<Port *>(*it); 463 464 switch(port->getPortType()) { 465 466 case Port::E_Audio: 467 if (encodePortToMotuEvents(static_cast<MotuAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) { 468 debugWarning("Could not encode port %s to MBLA events",(*it)->getName().c_str()); 469 no_problem=false; 470 } 471 break; 472 // midi is a packet based port, don't process 473 // case MotuPortInfo::E_Midi: 474 // break; 475 476 default: // ignore 477 break; 478 } 479 } 480 return no_problem; 481 } 482 483 bool 484 MotuTransmitStreamProcessor::transmitSilenceBlock(char *data, 485 unsigned int nevents, unsigned int offset) { 486 // This is the same as the non-silence version, except that is 487 // doesn't read from the port buffers. 450 488 bool no_problem = true; 451 452 489 for ( PortVectorIterator it = m_PeriodPorts.begin(); 453 it != m_PeriodPorts.end(); 454 ++it ) 455 { 456 if ( (*it)->isDisabled() ) { continue; }; 457 490 it != m_PeriodPorts.end(); 491 ++it ) { 458 492 //FIXME: make this into a static_cast when not DEBUG? 459 AmdtpPortInfo *pinfo = dynamic_cast<AmdtpPortInfo *> ( *it ); 460 assert ( pinfo ); // this should not fail!! 461 462 switch( pinfo->getFormat() ) 463 { 464 case AmdtpPortInfo::E_MBLA: 465 if( encodePortToMBLAEvents(static_cast<AmdtpAudioPort *>(*it), (quadlet_t *)data, offset, nevents) ) 466 { 467 debugWarning ( "Could not encode port %s to MBLA events", (*it)->getName().c_str() ); 468 no_problem = false; 493 Port *port=dynamic_cast<Port *>(*it); 494 495 switch(port->getPortType()) { 496 497 case Port::E_Audio: 498 if (encodeSilencePortToMotuEvents(static_cast<MotuAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) { 499 debugWarning("Could not encode port %s to MBLA events",(*it)->getName().c_str()); 500 no_problem = false; 501 } 502 break; 503 // midi is a packet based port, don't process 504 // case MotuPortInfo::E_Midi: 505 // break; 506 507 default: // ignore 508 break; 509 } 510 } 511 return no_problem; 512 } 513 514 /** 515 * @brief encode a packet for the packet-based ports 516 * 517 * @param data Packet data 518 * @param nevents number of events in data (including events of other ports & port types) 519 * @param dbc DataBlockCount value for this packet 520 * @return true if all successfull 521 */ 522 bool MotuTransmitStreamProcessor::encodePacketPorts(quadlet_t *data, unsigned int nevents, 523 unsigned int dbc) { 524 bool ok=true; 525 char byte; 526 527 // Use char here since the target address won't necessarily be 528 // aligned; use of an unaligned quadlet_t may cause issues on 529 // certain architectures. Besides, the target for MIDI data going 530 // directly to the MOTU isn't structured in quadlets anyway; it is a 531 // sequence of 3 unaligned bytes. 532 unsigned char *target = NULL; 533 534 for ( PortVectorIterator it = m_PacketPorts.begin(); 535 it != m_PacketPorts.end(); 536 ++it ) { 537 538 Port *port=static_cast<Port *>(*it); 539 assert(port); // this should not fail!! 540 541 // Currently the only packet type of events for MOTU 542 // is MIDI in mbla. However in future control data 543 // might also be sent via "packet" events. 544 // assert(pinfo->getFormat()==MotuPortInfo::E_Midi); 545 546 // FIXME: MIDI output is completely untested at present. 547 switch (port->getPortType()) { 548 case Port::E_Midi: { 549 MotuMidiPort *mp=static_cast<MotuMidiPort *>(*it); 550 551 // Send a byte if we can. MOTU MIDI data is 552 // sent using a 3-byte sequence starting at 553 // the port's position. For now we'll 554 // always send in the first event of a 555 // packet, but this might need refinement 556 // later. 557 if (mp->canRead()) { 558 mp->readEvent(&byte); 559 target = (unsigned char *)data + mp->getPosition(); 560 *(target++) = 0x01; 561 *(target++) = 0x00; 562 *(target++) = byte; 469 563 } 470 564 break; 471 case AmdtpPortInfo::E_SPDIF: // still unimplemented 472 break; 473 default: // ignore 474 break; 475 } 476 } 477 return no_problem; 478 } 479 480 bool 481 AmdtpTransmitStreamProcessor::transmitSilenceBlock( 482 char *data, unsigned int nevents, unsigned int offset) 483 { 484 bool no_problem = true; 485 for(PortVectorIterator it = m_PeriodPorts.begin(); 486 it != m_PeriodPorts.end(); 487 ++it ) 488 { 489 //FIXME: make this into a static_cast when not DEBUG? 490 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it); 491 assert(pinfo); // this should not fail!! 492 493 switch( pinfo->getFormat() ) 494 { 495 case AmdtpPortInfo::E_MBLA: 496 if ( encodeSilencePortToMBLAEvents(static_cast<AmdtpAudioPort *>(*it), (quadlet_t *)data, offset, nevents) ) 497 { 498 debugWarning("Could not encode port %s to MBLA events", (*it)->getName().c_str()); 499 no_problem = false; 500 } 501 break; 502 case AmdtpPortInfo::E_SPDIF: // still unimplemented 503 break; 504 default: // ignore 505 break; 506 } 507 } 508 return no_problem; 509 } 510 511 /** 512 * @brief decode a packet for the packet-based ports 513 * 514 * @param data Packet data 515 * @param nevents number of events in data (including events of other ports & port types) 516 * @param dbc DataBlockCount value for this packet 517 * @return true if all successfull 518 */ 519 bool AmdtpTransmitStreamProcessor::encodePacketPorts ( quadlet_t *data, unsigned int nevents, unsigned int dbc ) 520 { 521 bool ok=true; 522 quadlet_t byte; 523 524 quadlet_t *target_event=NULL; 525 unsigned int j; 526 527 for ( PortVectorIterator it = m_PacketPorts.begin(); 528 it != m_PacketPorts.end(); 529 ++it ) 530 { 531 532 #ifdef DEBUG 533 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *> ( *it ); 534 assert ( pinfo ); // this should not fail!! 535 536 // the only packet type of events for AMDTP is MIDI in mbla 537 assert ( pinfo->getFormat() ==AmdtpPortInfo::E_Midi ); 538 #endif 539 540 AmdtpMidiPort *mp=static_cast<AmdtpMidiPort *> ( *it ); 541 542 // we encode this directly (no function call) due to the high frequency 543 /* idea: 544 spec says: current_midi_port=(dbc+j)%8; 545 => if we start at (dbc+stream->location-1)%8, 546 we'll start at the right event for the midi port. 547 => if we increment j with 8, we stay at the right event. 548 */ 549 // FIXME: as we know in advance how big a packet is (syt_interval) we can 550 // predict how much loops will be present here 551 // first prefill the buffer with NO_DATA's on all time muxed channels 552 553 for ( j = ( dbc & 0x07 ) +mp->getLocation(); j < nevents; j += 8 ) 554 { 555 556 quadlet_t tmpval; 557 558 target_event= ( quadlet_t * ) ( data + ( ( j * m_dimension ) + mp->getPosition() ) ); 559 560 if ( mp->canRead() ) // we can send a byte 561 { 562 mp->readEvent ( &byte ); 563 byte &= 0xFF; 564 tmpval=htonl ( 565 IEC61883_AM824_SET_LABEL ( ( byte ) <<16, 566 IEC61883_AM824_LABEL_MIDI_1X ) ); 567 568 debugOutput ( DEBUG_LEVEL_ULTRA_VERBOSE, "MIDI port %s, pos=%d, loc=%d, dbc=%d, nevents=%d, dim=%d\n", 569 mp->getName().c_str(), mp->getPosition(), mp->getLocation(), dbc, nevents, m_dimension ); 570 debugOutput ( DEBUG_LEVEL_ULTRA_VERBOSE, "base=%p, target=%p, value=%08X\n", 571 data, target_event, tmpval ); 572 573 } 574 else 575 { 576 // can't send a byte, either because there is no byte, 577 // or because this would exceed the maximum rate 578 tmpval=htonl ( 579 IEC61883_AM824_SET_LABEL ( 0,IEC61883_AM824_LABEL_MIDI_NO_DATA ) ); 580 } 581 582 *target_event=tmpval; 583 } 584 585 } 565 } 566 default: 567 debugOutput(DEBUG_LEVEL_VERBOSE, "Unknown packet-type port type %d\n",port->getPortType()); 568 return ok; 569 } 570 } 571 586 572 return ok; 587 573 } 588 574 589 590 int AmdtpTransmitStreamProcessor::encodePortToMBLAEvents ( AmdtpAudioPort *p, quadlet_t *data, 591 unsigned int offset, unsigned int nevents ) 592 { 575 int MotuTransmitStreamProcessor::encodePortToMotuEvents(MotuAudioPort *p, quadlet_t *data, 576 unsigned int offset, unsigned int nevents) { 577 // Encodes nevents worth of data from the given port into the given buffer. The 578 // format of the buffer is precisely that which will be sent to the MOTU. 579 // The basic idea: 580 // iterate over the ports 581 // * get port buffer address 582 // * loop over events 583 // - pick right sample in event based upon PortInfo 584 // - convert sample from Port format (E_Int24, E_Float, ..) to MOTU 585 // native format 586 // 587 // We include the ability to start the transfer from the given offset within 588 // the port (expressed in frames) so the 'efficient' transfer method can be 589 // utilised. 590 593 591 unsigned int j=0; 594 592 595 quadlet_t *target_event; 596 597 target_event= ( quadlet_t * ) ( data + p->getPosition() ); 598 599 switch ( p->getDataType() ) 600 { 593 // Use char here since the target address won't necessarily be 594 // aligned; use of an unaligned quadlet_t may cause issues on certain 595 // architectures. Besides, the target (data going directly to the MOTU) 596 // isn't structured in quadlets anyway; it mainly consists of packed 597 // 24-bit integers. 598 unsigned char *target; 599 target = (unsigned char *)data + p->getPosition(); 600 601 switch(p->getDataType()) { 601 602 default: 602 603 case Port::E_Int24: 603 {604 quadlet_t *buffer= ( quadlet_t * ) ( p->getBufferAddress() );605 606 assert ( nevents + offset <= p->getBufferSize() );607 608 buffer+=offset;609 610 for ( j = 0; j < nevents; j += 1 ) // decode max nsamples611 604 { 612 *target_event = htonl ( ( * ( buffer ) & 0x00FFFFFF ) | 0x40000000 ); 613 buffer++; 614 target_event += m_dimension; 615 } 616 } 617 break; 605 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); 606 607 assert(nevents + offset <= p->getBufferSize()); 608 609 // Offset is in frames, but each port is only a single 610 // channel, so the number of frames is the same as the 611 // number of quadlets to offset (assuming the port buffer 612 // uses one quadlet per sample, which is the case currently). 613 buffer+=offset; 614 615 for(j = 0; j < nevents; j += 1) { // Decode nsamples 616 *target = (*buffer >> 16) & 0xff; 617 *(target+1) = (*buffer >> 8) & 0xff; 618 *(target+2) = (*buffer) & 0xff; 619 620 buffer++; 621 target+=m_event_size; 622 } 623 } 624 break; 618 625 case Port::E_Float: 619 {620 const float multiplier = ( float ) ( 0x7FFFFF00 );621 float *buffer= ( float * ) ( p->getBufferAddress() );622 623 assert ( nevents + offset <= p->getBufferSize() );624 625 buffer+=offset;626 627 for ( j = 0; j < nevents; j += 1 ) // decode max nsamples628 626 { 629 630 // don't care for overflow 631 float v = *buffer * multiplier; // v: -231 .. 231 632 unsigned int tmp = ( ( int ) v ); 633 *target_event = htonl ( ( tmp >> 8 ) | 0x40000000 ); 634 635 buffer++; 636 target_event += m_dimension; 637 } 638 } 639 break; 627 const float multiplier = (float)(0x7FFFFF); 628 float *buffer=(float *)(p->getBufferAddress()); 629 630 assert(nevents + offset <= p->getBufferSize()); 631 632 buffer+=offset; 633 634 for(j = 0; j < nevents; j += 1) { // decode max nsamples 635 unsigned int v = (int)(*buffer * multiplier); 636 *target = (v >> 16) & 0xff; 637 *(target+1) = (v >> 8) & 0xff; 638 *(target+2) = v & 0xff; 639 640 buffer++; 641 target+=m_event_size; 642 } 643 } 644 break; 640 645 } 641 646 642 647 return 0; 643 648 } 644 int AmdtpTransmitStreamProcessor::encodeSilencePortToMBLAEvents ( AmdtpAudioPort *p, quadlet_t *data, 645 unsigned int offset, unsigned int nevents ) 646 {649 650 int MotuTransmitStreamProcessor::encodeSilencePortToMotuEvents(MotuAudioPort *p, quadlet_t *data, 651 unsigned int offset, unsigned int nevents) { 647 652 unsigned int j=0; 648 649 quadlet_t *target_event; 650 651 target_event= ( quadlet_t * ) ( data + p->getPosition() ); 652 653 switch ( p->getDataType() ) 654 { 655 default: 653 unsigned char *target = (unsigned char *)data + p->getPosition(); 654 655 switch (p->getDataType()) { 656 default: 656 657 case Port::E_Int24: 657 658 case Port::E_Float: 658 { 659 for ( j = 0; j < nevents; j += 1 ) // decode max nsamples 660 { 661 *target_event = htonl ( 0x40000000 ); 662 target_event += m_dimension; 663 } 659 for (j = 0; j < nevents; j++) { 660 *target = *(target+1) = *(target+2) = 0; 661 target += m_event_size; 664 662 } 665 663 break; branches/ppalmers-streaming/src/libstreaming/motu/MotuTransmitStreamProcessor.h
r732 r733 22 22 */ 23 23 24 #ifndef __FFADO_ AMDTPTRANSMITSTREAMPROCESSOR__25 #define __FFADO_ AMDTPTRANSMITSTREAMPROCESSOR__24 #ifndef __FFADO_MOTUTRANSMITSTREAMPROCESSOR__ 25 #define __FFADO_MOTUTRANSMITSTREAMPROCESSOR__ 26 26 27 27 /** 28 * This class implements IEC61883-6 / AM824 / AMDTPbased streaming28 * This class implements MOTU based streaming 29 29 */ 30 30 … … 34 34 #include "../util/cip.h" 35 35 36 #include <libiec61883/iec61883.h>37 #include <pthread.h>38 39 #define AMDTP_MAX_PACKET_SIZE 204840 41 #define IEC61883_STREAM_TYPE_MIDI 0x0D42 #define IEC61883_STREAM_TYPE_SPDIF 0x0043 #define IEC61883_STREAM_TYPE_MBLA 0x0644 45 #define IEC61883_AM824_LABEL_MASK 0xFF00000046 #define IEC61883_AM824_GET_LABEL(x) (((x) & 0xFF000000) >> 24)47 #define IEC61883_AM824_SET_LABEL(x,y) ((x) | ((y)<<24))48 49 #define IEC61883_AM824_LABEL_MIDI_NO_DATA 0x8050 #define IEC61883_AM824_LABEL_MIDI_1X 0x8151 #define IEC61883_AM824_LABEL_MIDI_2X 0x8252 #define IEC61883_AM824_LABEL_MIDI_3X 0x8353 54 36 namespace Streaming { 55 37 56 38 class Port; 57 class AmdtpAudioPort; 58 class AmdtpMidiPort; 39 class MotuAudioPort; 59 40 60 41 /*! 61 \brief The Base Class for an AMDTPtransmit stream processor42 \brief The Base Class for an MOTU transmit stream processor 62 43 63 44 This class implements a TransmitStreamProcessor that multiplexes Ports 64 into AMDTPstreams.45 into MOTU streams. 65 46 66 47 */ 67 class AmdtpTransmitStreamProcessor48 class MotuTransmitStreamProcessor 68 49 : public StreamProcessor 69 50 { … … 71 52 public: 72 53 /** 73 * Create a AMDTP transmit StreamProcessor 74 * @param port 1394 port 75 * @param framerate frame rate 76 * @param dimension number of substreams in the ISO stream 77 * (midi-muxed is only one stream) 54 * Create a MOTU transmit StreamProcessor 78 55 */ 79 AmdtpTransmitStreamProcessor(int port, int dimension);80 virtual ~ AmdtpTransmitStreamProcessor() {};56 MotuTransmitStreamProcessor(int port, unsigned int event_size); 57 virtual ~MotuTransmitStreamProcessor() {}; 81 58 82 59 enum eChildReturnValue generatePacketHeader(unsigned char *data, unsigned int *length, … … 95 72 96 73 public: 97 virtual unsigned int getEventSize() 98 {return 4;}; 99 virtual unsigned int getMaxPacketSize() 100 {return 4 * (2 + m_syt_interval * m_dimension);}; 101 virtual unsigned int getEventsPerFrame() 102 { return m_dimension; }; 103 virtual unsigned int getNominalFramesPerPacket() 104 {return m_syt_interval;}; 105 virtual unsigned int getPacketsPerPeriod(); 106 virtual unsigned int getNominalPacketsNeeded(unsigned int nframes); 74 virtual unsigned int getEventSize() 75 {return m_event_size;}; 76 virtual unsigned int getMaxPacketSize(); 77 virtual unsigned int getEventsPerFrame() 78 { return 1; }; // FIXME: check 79 virtual unsigned int getNominalFramesPerPacket(); 107 80 108 81 protected: … … 111 84 112 85 private: 113 unsigned int fillNoDataPacketHeader( struct iec61883_packet *packet, unsigned int* length);114 unsigned int fillDataPacketHeader( struct iec61883_packet *packet, unsigned int* length, uint32_t ts);86 unsigned int fillNoDataPacketHeader(quadlet_t *data, unsigned int* length); 87 unsigned int fillDataPacketHeader(quadlet_t *data, unsigned int* length, uint32_t ts); 115 88 116 89 int transmitBlock(char *data, unsigned int nevents, … … 120 93 unsigned int dbc); 121 94 122 int encodePortToM BLAEvents(AmdtpAudioPort *, quadlet_t *data,95 int encodePortToMotuEvents(MotuAudioPort *, quadlet_t *data, 123 96 unsigned int offset, unsigned int nevents); 124 int encodeSilencePortToM BLAEvents(AmdtpAudioPort *, quadlet_t *data,97 int encodeSilencePortToMotuEvents(MotuAudioPort *, quadlet_t *data, 125 98 unsigned int offset, unsigned int nevents); 126 99 127 struct iec61883_cip m_cip_status; 128 int m_dimension; 129 unsigned int m_syt_interval; 130 int m_fdf; 131 unsigned int m_dbc; 100 /* 101 * An iso packet mostly consists of multiple events. m_event_size 102 * is the size of a single 'event' in bytes. 103 */ 104 unsigned int m_event_size; 105 106 // Keep track of transmission data block count 107 unsigned int m_tx_dbc; 108 132 109 }; 133 110 134 111 } // end of namespace Streaming 135 112 136 #endif /* __FFADO_ AMDTPTRANSMITSTREAMPROCESSOR__ */113 #endif /* __FFADO_MOTUTRANSMITSTREAMPROCESSOR__ */ 137 114 branches/ppalmers-streaming/src/motu/motu_avdevice.cpp
r705 r733 32 32 #include "debugmodule/debugmodule.h" 33 33 34 #include "libstreaming/motu/MotuStreamProcessor.h" 34 #include "libstreaming/motu/MotuReceiveStreamProcessor.h" 35 #include "libstreaming/motu/MotuTransmitStreamProcessor.h" 35 36 #include "libstreaming/motu/MotuPort.h" 36 37 … … 523 524 524 525 m_receiveProcessor=new Streaming::MotuReceiveStreamProcessor( 525 m_p1394Service->getPort(), samp_freq,event_size_in);526 m_p1394Service->getPort(), event_size_in); 526 527 527 528 // The first thing is to initialize the processor. This creates the … … 593 594 // Do the same for the transmit processor 594 595 m_transmitProcessor=new Streaming::MotuTransmitStreamProcessor( 595 m_p1394Service->getPort(), getSamplingFrequency(),event_size_out);596 m_p1394Service->getPort(), event_size_out); 596 597 597 598 m_transmitProcessor->setVerboseLevel(getDebugLevel()); branches/ppalmers-streaming/src/motu/motu_avdevice.h
r705 r733 31 31 #include "libavc/avc_definitions.h" 32 32 33 #include "libstreaming/motu/MotuStreamProcessor.h" 33 #include "libstreaming/motu/MotuReceiveStreamProcessor.h" 34 #include "libstreaming/motu/MotuTransmitStreamProcessor.h" 34 35 35 36 #define MOTUFW_BASE_ADDR 0xfffff0000000ULL branches/ppalmers-streaming/src/SConscript
r730 r733 123 123 libstreaming/motu/MotuPort.cpp \ 124 124 libstreaming/motu/MotuPortInfo.cpp \ 125 libstreaming/motu/MotuStreamProcessor.cpp \ 125 libstreaming/motu/MotuReceiveStreamProcessor.cpp \ 126 libstreaming/motu/MotuTransmitStreamProcessor.cpp \ 126 127 ' ) 127 128