Changeset 712
- Timestamp:
- 11/11/07 07:52:01 (16 years ago)
- Files:
-
- branches/ppalmers-streaming/src/bebob/bebob_avdevice.h (modified) (1 diff)
- branches/ppalmers-streaming/src/bounce/bounce_avdevice.h (modified) (1 diff)
- branches/ppalmers-streaming/src/dice/dice_avdevice.cpp (modified) (2 diffs)
- branches/ppalmers-streaming/src/dice/dice_avdevice.h (modified) (1 diff)
- branches/ppalmers-streaming/src/genericavc/avc_avdevice.h (modified) (1 diff)
- branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.cpp (moved) (moved from branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpStreamProcessor.cpp) (9 diffs)
- branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.h (copied) (copied from branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpStreamProcessor.h) (4 diffs)
- branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpSlaveStreamProcessor.h (modified) (1 diff)
- branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp (copied) (copied from branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpStreamProcessor.cpp) (7 diffs)
- branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.h (moved) (moved from branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpStreamProcessor.h) (3 diffs)
- branches/ppalmers-streaming/src/libstreaming/generic/StreamProcessor.cpp (modified) (1 diff)
- branches/ppalmers-streaming/src/libstreaming/generic/StreamProcessor.h (modified) (2 diffs)
- branches/ppalmers-streaming/src/libstreaming/StreamProcessorManager.cpp (modified) (7 diffs)
- branches/ppalmers-streaming/src/libstreaming/util/cycletimer.h (modified) (1 diff)
- branches/ppalmers-streaming/src/libutil/TimestampedBuffer.cpp (modified) (6 diffs)
- branches/ppalmers-streaming/src/libutil/TimestampedBuffer.h (modified) (1 diff)
- branches/ppalmers-streaming/src/maudio/maudio_avdevice.h (modified) (1 diff)
- branches/ppalmers-streaming/src/SConscript (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/ppalmers-streaming/src/bebob/bebob_avdevice.h
r705 r712 42 42 #include "bebob/bebob_mixer.h" 43 43 44 #include "libstreaming/amdtp/AmdtpStreamProcessor.h" 44 #include "libstreaming/amdtp/AmdtpReceiveStreamProcessor.h" 45 #include "libstreaming/amdtp/AmdtpTransmitStreamProcessor.h" 45 46 #include "libstreaming/amdtp/AmdtpPort.h" 46 47 #include "libstreaming/amdtp/AmdtpPortInfo.h" branches/ppalmers-streaming/src/bounce/bounce_avdevice.h
r705 r712 30 30 #include "libavc/general/avc_extended_cmd_generic.h" 31 31 32 #include "libstreaming/amdtp/AmdtpStreamProcessor.h" 32 #include "libstreaming/amdtp/AmdtpReceiveStreamProcessor.h" 33 #include "libstreaming/amdtp/AmdtpTransmitStreamProcessor.h" 33 34 #include "libstreaming/amdtp/AmdtpPort.h" 34 35 #include "libstreaming/amdtp/AmdtpPortInfo.h" branches/ppalmers-streaming/src/dice/dice_avdevice.cpp
r705 r712 28 28 #include "libieee1394/ieee1394service.h" 29 29 30 #include "libstreaming/amdtp/AmdtpStreamProcessor.h"31 32 30 #include "debugmodule/debugmodule.h" 33 31 … … 51 49 // vendor id, model id, vendor name, model name 52 50 {FW_VENDORID_TCAT, 0x00000002, "TCAT", "DiceII EVM"}, 51 {FW_VENDORID_TCAT, 0x00000004, "TCAT", "DiceII EVM (vxx)"}, 53 52 }; 54 53 branches/ppalmers-streaming/src/dice/dice_avdevice.h
r705 r712 30 30 #include "libavc/avc_definitions.h" 31 31 32 #include "libstreaming/amdtp/AmdtpStreamProcessor.h" 32 #include "libstreaming/amdtp/AmdtpReceiveStreamProcessor.h" 33 #include "libstreaming/amdtp/AmdtpTransmitStreamProcessor.h" 33 34 #include "libstreaming/amdtp/AmdtpPort.h" 34 35 #include "libieee1394/ARMHandler.h" branches/ppalmers-streaming/src/genericavc/avc_avdevice.h
r705 r712 34 34 #include "libavc/general/avc_plug.h" 35 35 36 #include "libstreaming/amdtp/AmdtpStreamProcessor.h" 36 #include "libstreaming/amdtp/AmdtpReceiveStreamProcessor.h" 37 #include "libstreaming/amdtp/AmdtpTransmitStreamProcessor.h" 37 38 #include "libstreaming/amdtp/AmdtpPort.h" 38 39 #include "libstreaming/amdtp/AmdtpPortInfo.h" branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.cpp
r709 r712 22 22 */ 23 23 24 #include "Amdtp StreamProcessor.h"24 #include "AmdtpReceiveStreamProcessor.h" 25 25 #include "AmdtpPort.h" 26 26 … … 39 39 namespace Streaming { 40 40 41 /* transmit */42 AmdtpTransmitStreamProcessor::AmdtpTransmitStreamProcessor(int port, int framerate, int dimension)43 : TransmitStreamProcessor(port, framerate), m_dimension(dimension)44 , m_last_timestamp(0), m_dbc(0), m_ringbuffer_size_frames(0)45 {}46 47 /**48 * @return49 */50 bool AmdtpTransmitStreamProcessor::init() {51 52 debugOutput( DEBUG_LEVEL_VERBOSE, "Initializing (%p)...\n");53 // call the parent init54 // this has to be done before allocating the buffers,55 // because this sets the buffersizes from the processormanager56 if(!TransmitStreamProcessor::init()) {57 debugFatal("Could not do base class init (%p)\n",this);58 return false;59 }60 return true;61 }62 63 enum raw1394_iso_disposition64 AmdtpTransmitStreamProcessor::getPacket(unsigned char *data, unsigned int *length,65 unsigned char *tag, unsigned char *sy,66 int cycle, unsigned int dropped, unsigned int max_length) {67 struct iec61883_packet *packet = (struct iec61883_packet *) data;68 69 if (cycle<0) {70 debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE,"Xmit handler for cycle %d, (running=%d)\n",71 cycle, m_running);72 *tag = 0;73 *sy = 0;74 *length=0;75 return RAW1394_ISO_OK;76 }77 78 debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE,"Xmit handler for cycle %d, (running=%d)\n",79 cycle, m_running);80 81 m_last_cycle=cycle;82 83 #ifdef DEBUG84 if(dropped>0) {85 debugWarning("Dropped %d packets on cycle %d\n",dropped, cycle);86 }87 #endif88 89 // calculate & preset common values90 91 /* Our node ID can change after a bus reset, so it is best to fetch92 * our node ID for each packet. */93 packet->sid = getNodeId() & 0x3f;94 95 packet->dbs = m_dimension;96 packet->fn = 0;97 packet->qpc = 0;98 packet->sph = 0;99 packet->reserved = 0;100 packet->dbc = m_dbc;101 packet->eoh1 = 2;102 packet->fmt = IEC61883_FMT_AMDTP;103 104 *tag = IEC61883_TAG_WITH_CIP;105 *sy = 0;106 107 // determine if we want to send a packet or not108 // note that we can't use getCycleTimer directly here,109 // because packets are queued in advance. This means that110 // we the packet we are constructing will be sent out111 // on 'cycle', not 'now'.112 unsigned int ctr=m_handler->getCycleTimer();113 int now_cycles = (int)CYCLE_TIMER_GET_CYCLES(ctr);114 115 // the difference between the cycle this116 // packet is intended for and 'now'117 int cycle_diff = diffCycles(cycle, now_cycles);118 119 #ifdef DEBUG120 if(m_running && (cycle_diff < 0)) {121 debugWarning("Requesting packet for cycle %04d which is in the past (now=%04dcy)\n",122 cycle, now_cycles);123 }124 125 // keep track of the lag126 m_PacketStat.mark(cycle_diff);127 #endif128 129 // as long as the cycle parameter is not in sync with130 // the current time, the stream is considered not131 // to be 'running'132 // NOTE: this works only at startup133 if (!m_running && cycle_diff >= 0 && cycle >= 0) {134 debugOutput(DEBUG_LEVEL_VERBOSE, "Xmit StreamProcessor %p started running at cycle %d\n",this, cycle);135 m_running=true;136 }137 138 signed int fc;139 uint64_t presentation_time;140 unsigned int presentation_cycle;141 int cycles_until_presentation;142 143 uint64_t transmit_at_time;144 unsigned int transmit_at_cycle;145 int cycles_until_transmit;146 147 // FIXME: should become a define148 // the absolute minimum number of cycles we want to transmit149 // a packet ahead of the presentation time. The nominal time150 // the packet is transmitted ahead of the presentation time is151 // given by TRANSMIT_TRANSFER_DELAY (in ticks), but in case we152 // are too late for that, this constant defines how late we can153 // be.154 const int min_cycles_before_presentation = 1;155 // FIXME: should become a define156 // the absolute maximum number of cycles we want to transmit157 // a packet ahead of the ideal transmit time. The nominal time158 // the packet is transmitted ahead of the presentation time is159 // given by TRANSMIT_TRANSFER_DELAY (in ticks), but we can send160 // packets early if we want to. (not completely according to spec)161 const int max_cycles_to_transmit_early = 1;162 163 if( !m_running || !m_data_buffer->isEnabled() ) {164 debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE,165 "Not running (%d) or buffer not enabled (enabled=%d)\n",166 m_running, m_data_buffer->isEnabled());167 168 // not running or not enabled169 goto send_empty_packet;170 }171 172 try_block_of_frames:173 debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, "Try for cycle %d\n", cycle);174 // check whether the packet buffer has packets for us to send.175 // the base timestamp is the one of the next sample in the buffer176 ffado_timestamp_t ts_head_tmp;177 m_data_buffer->getBufferHeadTimestamp(&ts_head_tmp, &fc); // thread safe178 179 // the timestamp gives us the time at which we want the sample block180 // to be output by the device181 presentation_time=(uint64_t)ts_head_tmp;182 183 // now we calculate the time when we have to transmit the sample block184 transmit_at_time = substractTicks(presentation_time, TRANSMIT_TRANSFER_DELAY);185 186 // calculate the cycle this block should be presented in187 // (this is just a virtual calculation since at that time it should188 // already be in the device's buffer)189 presentation_cycle = (unsigned int)(TICKS_TO_CYCLES( presentation_time ));190 191 // calculate the cycle this block should be transmitted in192 transmit_at_cycle = (unsigned int)(TICKS_TO_CYCLES( transmit_at_time ));193 194 // we can check whether this cycle is within the 'window' we have195 // to send this packet.196 // first calculate the number of cycles left before presentation time197 cycles_until_presentation = diffCycles( presentation_cycle, cycle );198 199 // we can check whether this cycle is within the 'window' we have200 // to send this packet.201 // first calculate the number of cycles left before presentation time202 cycles_until_transmit = diffCycles( transmit_at_cycle, cycle );203 204 // two different options:205 // 1) there are not enough frames for one packet206 // => determine wether this is a problem, since we might still207 // have some time to send it208 // 2) there are enough packets209 // => determine whether we have to send them in this packet210 if (fc < (signed int)m_syt_interval) {211 m_PacketStat.signal(0);212 // not enough frames in the buffer,213 debugOutput(DEBUG_LEVEL_VERBOSE,214 "Insufficient frames: N=%02d, CY=%04u, TC=%04u, CUT=%04d\n",215 fc, cycle, transmit_at_cycle, cycles_until_transmit);216 // we can still postpone the queueing of the packets217 // if we are far enough ahead of the presentation time218 if( cycles_until_presentation <= min_cycles_before_presentation ) {219 m_PacketStat.signal(1);220 // we are too late221 // meaning that we in some sort of xrun state222 // signal xrun situation ??HERE??223 m_xruns++;224 // we send an empty packet on this cycle225 goto send_empty_packet; // UGLY but effective226 } else {227 m_PacketStat.signal(2);228 // there is still time left to send the packet229 // we want the system to give this packet another go230 // goto try_packet_again; // UGLY but effective231 // unfortunatly the try_again doesn't work very well,232 // so we'll have to either usleep(one cycle) and goto try_block_of_frames233 234 // or just fill this with an empty packet235 // if we have to do this too often, the presentation time will236 // get too close and we're in trouble237 goto send_empty_packet; // UGLY but effective238 }239 } else {240 m_PacketStat.signal(3);241 // there are enough frames, so check the time they are intended for242 // all frames have a certain 'time window' in which they can be sent243 // this corresponds to the range of the timestamp mechanism:244 // we can send a packet 15 cycles in advance of the 'presentation time'245 // in theory we can send the packet up till one cycle before the presentation time,246 // however this is not very smart.247 248 // There are 3 options:249 // 1) the frame block is too early250 // => send an empty packet251 // 2) the frame block is within the window252 // => send it253 // 3) the frame block is too late254 // => discard (and raise xrun?)255 // get next block of frames and repeat256 257 if (cycles_until_transmit <= max_cycles_to_transmit_early) {258 m_PacketStat.signal(4);259 // it's time send the packet260 goto send_packet; // UGLY but effective261 } else if (cycles_until_transmit < 0) {262 // we are too late263 debugOutput(DEBUG_LEVEL_VERBOSE,264 "Too late: CY=%04u, TC=%04u, CUT=%04d, TSP=%011llu (%04u)\n",265 cycle,266 transmit_at_cycle, cycles_until_transmit,267 presentation_time, (unsigned int)TICKS_TO_CYCLES(presentation_time));268 269 // however, if we can send this sufficiently before the presentation270 // time, it could be harmless.271 // NOTE: dangerous since the device has no way of reporting that it didn't get272 // this packet on time.273 if ( cycles_until_presentation <= min_cycles_before_presentation ) {274 m_PacketStat.signal(5);275 // we are not that late and can still try to transmit the packet276 goto send_packet; // UGLY but effective277 } else { // definitely too late278 m_PacketStat.signal(6);279 // remove the samples280 m_data_buffer->dropFrames(m_syt_interval);281 // signal some xrun situation ??HERE??282 m_xruns++;283 // try a new block of frames284 goto try_block_of_frames; // UGLY but effective285 }286 } else {287 m_PacketStat.signal(7);288 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,289 "Too early: CY=%04u, TC=%04u, CUT=%04d, TST=%011llu (%04u), TSP=%011llu (%04u)\n",290 cycle,291 transmit_at_cycle, cycles_until_transmit,292 transmit_at_time, (unsigned int)TICKS_TO_CYCLES(transmit_at_time),293 presentation_time, (unsigned int)TICKS_TO_CYCLES(presentation_time));294 #ifdef DEBUG295 if (cycles_until_transmit > max_cycles_to_transmit_early + 1) {296 debugOutput(DEBUG_LEVEL_VERBOSE,297 "Way too early: CY=%04u, TC=%04u, CUT=%04d, TST=%011llu (%04u), TSP=%011llu (%04u)\n",298 cycle,299 transmit_at_cycle, cycles_until_transmit,300 transmit_at_time, (unsigned int)TICKS_TO_CYCLES(transmit_at_time),301 presentation_time, (unsigned int)TICKS_TO_CYCLES(presentation_time));302 }303 #endif304 // we are too early, send only an empty packet305 goto send_empty_packet; // UGLY but effective306 }307 }308 309 debugFatal("Should never reach this code!\n");310 return RAW1394_ISO_ERROR;311 312 send_empty_packet:313 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "XMIT NONE: CY=%04u, TSP=%011llu (%04u)\n",314 cycle,315 presentation_time, (unsigned int)TICKS_TO_CYCLES(presentation_time));316 317 m_dbc += fillNoDataPacketHeader(packet, length);318 return RAW1394_ISO_DEFER;319 320 send_packet:321 if (m_data_buffer->readFrames(m_syt_interval, (char *)(data + 8))) {322 m_dbc += fillDataPacketHeader(packet, length, presentation_time);323 324 // process all ports that should be handled on a per-packet base325 // this is MIDI for AMDTP (due to the need of DBC)326 if (!encodePacketPorts((quadlet_t *)(data+8), m_syt_interval, packet->dbc)) {327 debugWarning("Problem encoding Packet Ports\n");328 }329 330 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "XMIT DATA: CY=%04u, TST=%011llu (%04u), TSP=%011llu (%04u)\n",331 cycle,332 transmit_at_time, (unsigned int)TICKS_TO_CYCLES(transmit_at_time),333 presentation_time, (unsigned int)TICKS_TO_CYCLES(presentation_time));334 335 return RAW1394_ISO_OK;336 }337 338 // the ISO AGAIN does not work very well...339 // try_packet_again:340 //341 // debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "XMIT RETRY: CY=%04u, TSP=%011llu (%04u)\n",342 // cycle,343 // presentation_time, (unsigned int)TICKS_TO_CYCLES(presentation_time));344 // return RAW1394_ISO_AGAIN;345 346 // else:347 debugFatal("This is impossible, since we checked the buffer size before!\n");348 return RAW1394_ISO_ERROR;349 }350 351 unsigned int AmdtpTransmitStreamProcessor::fillDataPacketHeader(352 struct iec61883_packet *packet, unsigned int* length,353 uint32_t ts) {354 355 packet->fdf = m_fdf;356 357 // convert the timestamp to SYT format358 uint16_t timestamp_SYT = TICKS_TO_SYT(ts);359 packet->syt = ntohs(timestamp_SYT);360 361 *length = m_syt_interval*sizeof(quadlet_t)*m_dimension + 8;362 363 return m_syt_interval;364 }365 366 unsigned int AmdtpTransmitStreamProcessor::fillNoDataPacketHeader(367 struct iec61883_packet *packet, unsigned int* length) {368 369 // no-data packets have syt=0xFFFF370 // and have the usual amount of events as dummy data (?)371 packet->fdf = IEC61883_FDF_NODATA;372 packet->syt = 0xffff;373 374 // FIXME: either make this a setting or choose375 bool send_payload=true;376 if(send_payload) {377 // this means no-data packets with payload (DICE doesn't like that)378 *length = 2*sizeof(quadlet_t) + m_syt_interval * m_dimension * sizeof(quadlet_t);379 return m_syt_interval;380 } else {381 // dbc is not incremented382 // this means no-data packets without payload383 *length = 2*sizeof(quadlet_t);384 return 0;385 }386 }387 388 bool AmdtpTransmitStreamProcessor::prefill() {389 390 debugOutput( DEBUG_LEVEL_VERBOSE, "Prefill transmit buffers...\n");391 392 if(!transferSilence(m_ringbuffer_size_frames)) {393 debugFatal("Could not prefill transmit stream\n");394 return false;395 }396 397 return true;398 }399 400 bool AmdtpTransmitStreamProcessor::reset() {401 402 debugOutput( DEBUG_LEVEL_VERBOSE, "Resetting...\n");403 404 // reset the statistics405 m_PeriodStat.reset();406 m_PacketStat.reset();407 m_WakeupStat.reset();408 409 m_data_buffer->setTickOffset(0);410 411 // reset all non-device specific stuff412 // i.e. the iso stream and the associated ports413 if(!TransmitStreamProcessor::reset()) {414 debugFatal("Could not do base class reset\n");415 return false;416 }417 418 // we should prefill the event buffer419 if (!prefill()) {420 debugFatal("Could not prefill buffers\n");421 return false;422 }423 424 return true;425 }426 427 bool AmdtpTransmitStreamProcessor::prepare() {428 m_PeriodStat.setName("XMT PERIOD");429 m_PacketStat.setName("XMT PACKET");430 m_WakeupStat.setName("XMT WAKEUP");431 432 debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this);433 434 // prepare all non-device specific stuff435 // i.e. the iso stream and the associated ports436 if(!TransmitStreamProcessor::prepare()) {437 debugFatal("Could not prepare base class\n");438 return false;439 }440 441 switch (m_framerate) {442 case 32000:443 m_syt_interval = 8;444 m_fdf = IEC61883_FDF_SFC_32KHZ;445 break;446 case 44100:447 m_syt_interval = 8;448 m_fdf = IEC61883_FDF_SFC_44K1HZ;449 break;450 default:451 case 48000:452 m_syt_interval = 8;453 m_fdf = IEC61883_FDF_SFC_48KHZ;454 break;455 case 88200:456 m_syt_interval = 16;457 m_fdf = IEC61883_FDF_SFC_88K2HZ;458 break;459 case 96000:460 m_syt_interval = 16;461 m_fdf = IEC61883_FDF_SFC_96KHZ;462 break;463 case 176400:464 m_syt_interval = 32;465 m_fdf = IEC61883_FDF_SFC_176K4HZ;466 break;467 case 192000:468 m_syt_interval = 32;469 m_fdf = IEC61883_FDF_SFC_192KHZ;470 break;471 }472 473 iec61883_cip_init (474 &m_cip_status,475 IEC61883_FMT_AMDTP,476 m_fdf,477 m_framerate,478 m_dimension,479 m_syt_interval);480 481 // prepare the framerate estimate482 float ticks_per_frame = (TICKS_PER_SECOND*1.0) / ((float)m_framerate);483 m_ticks_per_frame=ticks_per_frame;484 485 // initialize internal buffer486 m_ringbuffer_size_frames=m_nb_buffers * m_period;487 488 assert(m_data_buffer);489 m_data_buffer->setBufferSize(m_ringbuffer_size_frames);490 m_data_buffer->setEventSize(sizeof(quadlet_t));491 m_data_buffer->setEventsPerFrame(m_dimension);492 493 m_data_buffer->setUpdatePeriod(m_period);494 m_data_buffer->setNominalRate(ticks_per_frame);495 496 m_data_buffer->setWrapValue(128L*TICKS_PER_SECOND);497 498 m_data_buffer->prepare();499 500 // set the parameters of ports we can:501 // we want the audio ports to be period buffered,502 // and the midi ports to be packet buffered503 for ( PortVectorIterator it = m_Ports.begin();504 it != m_Ports.end();505 ++it )506 {507 debugOutput(DEBUG_LEVEL_VERBOSE, "Setting up port %s\n",(*it)->getName().c_str());508 if(!(*it)->setBufferSize(m_period)) {509 debugFatal("Could not set buffer size to %d\n",m_period);510 return false;511 }512 513 514 switch ((*it)->getPortType()) {515 case Port::E_Audio:516 if(!(*it)->setSignalType(Port::E_PeriodSignalled)) {517 debugFatal("Could not set signal type to PeriodSignalling");518 return false;519 }520 debugWarning("---------------- ! Doing hardcoded test setup ! --------------\n");521 // buffertype and datatype are dependant on the API522 if(!(*it)->setBufferType(Port::E_PointerBuffer)) {523 debugFatal("Could not set buffer type");524 return false;525 }526 if(!(*it)->useExternalBuffer(true)) {527 debugFatal("Could not set external buffer usage");528 return false;529 }530 531 if(!(*it)->setDataType(Port::E_Float)) {532 debugFatal("Could not set data type");533 return false;534 }535 536 537 break;538 case Port::E_Midi:539 if(!(*it)->setSignalType(Port::E_PacketSignalled)) {540 debugFatal("Could not set signal type to PeriodSignalling");541 return false;542 }543 544 // we use a timing unit of 10ns545 // this makes sure that for the max syt interval546 // we don't have rounding, and keeps the numbers low547 // we have 1 slot every 8 events548 // we have syt_interval events per packet549 // => syt_interval/8 slots per packet550 // packet rate is 8000pkt/sec => interval=125us551 // so the slot interval is (1/8000)/(syt_interval/8)552 // or: 1/(1000 * syt_interval) sec553 // which is 1e9/(1000*syt_interval) nsec554 // or 100000/syt_interval 'units'555 // the event interval is fixed to 320us = 32000 'units'556 if(!(*it)->useRateControl(true,(100000/m_syt_interval),32000, false)) {557 debugFatal("Could not set signal type to PeriodSignalling");558 return false;559 }560 561 // buffertype and datatype are dependant on the API562 debugWarning("---------------- ! Doing hardcoded test setup ! --------------\n");563 // buffertype and datatype are dependant on the API564 if(!(*it)->setBufferType(Port::E_RingBuffer)) {565 debugFatal("Could not set buffer type");566 return false;567 }568 if(!(*it)->setDataType(Port::E_MidiEvent)) {569 debugFatal("Could not set data type");570 return false;571 }572 break;573 default:574 debugWarning("Unsupported port type specified\n");575 break;576 }577 }578 579 // the API specific settings of the ports should already be set,580 // as this is called from the processorManager->prepare()581 // so we can init the ports582 if(!initPorts()) {583 debugFatal("Could not initialize ports!\n");584 return false;585 }586 587 if(!preparePorts()) {588 debugFatal("Could not initialize ports!\n");589 return false;590 }591 592 debugOutput( DEBUG_LEVEL_VERBOSE, "Prepared for:\n");593 debugOutput( DEBUG_LEVEL_VERBOSE, " Samplerate: %d, FDF: %d, DBS: %d, SYT: %d\n",594 m_framerate,m_fdf,m_dimension,m_syt_interval);595 debugOutput( DEBUG_LEVEL_VERBOSE, " PeriodSize: %d, NbBuffers: %d\n",596 m_period,m_nb_buffers);597 debugOutput( DEBUG_LEVEL_VERBOSE, " Port: %d, Channel: %d\n",598 m_port,m_channel);599 600 return true;601 602 }603 604 bool AmdtpTransmitStreamProcessor::prepareForStart() {605 return true;606 }607 608 bool AmdtpTransmitStreamProcessor::prepareForStop() {609 return true;610 }611 612 bool AmdtpTransmitStreamProcessor::prepareForEnable(uint64_t time_to_enable_at) {613 614 if (!StreamProcessor::prepareForEnable(time_to_enable_at)) {615 debugError("StreamProcessor::prepareForEnable failed\n");616 return false;617 }618 619 return true;620 }621 622 bool AmdtpTransmitStreamProcessor::transferSilence(unsigned int nframes) {623 bool retval;624 625 char *dummybuffer=(char *)calloc(sizeof(quadlet_t),nframes*m_dimension);626 627 transmitSilenceBlock(dummybuffer, nframes, 0);628 629 // add the silence data to the ringbuffer630 if(m_data_buffer->writeFrames(nframes, dummybuffer, 0)) {631 retval=true;632 } else {633 debugWarning("Could not write to event buffer\n");634 retval=false;635 }636 637 free(dummybuffer);638 639 return retval;640 }641 642 bool AmdtpTransmitStreamProcessor::putFrames(unsigned int nbframes, int64_t ts) {643 m_PeriodStat.mark(m_data_buffer->getBufferFill());644 debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, "AmdtpTransmitStreamProcessor::putFrames(%d, %llu)\n", nbframes, ts);645 646 // transfer the data647 m_data_buffer->blockProcessWriteFrames(nbframes, ts);648 649 debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, " New timestamp: %llu\n", ts);650 651 return true; // FIXME: what about failure?652 }653 654 bool AmdtpTransmitStreamProcessor::putFramesDry(unsigned int nbframes, int64_t ts) {655 m_PeriodStat.mark(m_data_buffer->getBufferFill());656 debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, "AmdtpTransmitStreamProcessor::putFramesDry(%d, %llu)\n", nbframes, ts);657 658 bool retval;659 char dummybuffer[sizeof(quadlet_t)*nbframes*m_dimension];660 661 transmitSilenceBlock(dummybuffer, nbframes, 0);662 // add the silence data to the ringbuffer663 if(m_data_buffer->writeFrames(nbframes, dummybuffer, ts)) {664 retval=true;665 } else {666 debugWarning("Could not write to event buffer\n");667 retval=false;668 }669 670 debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, " New timestamp: %llu\n", ts);671 return retval;672 }673 674 /*675 * write received events to the stream ringbuffers.676 */677 678 bool AmdtpTransmitStreamProcessor::processWriteBlock(char *data,679 unsigned int nevents, unsigned int offset)680 {681 bool no_problem=true;682 683 for ( PortVectorIterator it = m_PeriodPorts.begin();684 it != m_PeriodPorts.end();685 ++it )686 {687 688 if((*it)->isDisabled()) {continue;};689 690 //FIXME: make this into a static_cast when not DEBUG?691 692 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);693 assert(pinfo); // this should not fail!!694 695 switch(pinfo->getFormat()) {696 case AmdtpPortInfo::E_MBLA:697 if(encodePortToMBLAEvents(static_cast<AmdtpAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) {698 debugWarning("Could not encode port %s to MBLA events",(*it)->getName().c_str());699 no_problem=false;700 }701 break;702 case AmdtpPortInfo::E_SPDIF: // still unimplemented703 break;704 default: // ignore705 break;706 }707 }708 return no_problem;709 710 }711 712 int AmdtpTransmitStreamProcessor::transmitSilenceBlock(char *data,713 unsigned int nevents, unsigned int offset)714 {715 int problem=0;716 717 for ( PortVectorIterator it = m_PeriodPorts.begin();718 it != m_PeriodPorts.end();719 ++it )720 {721 722 //FIXME: make this into a static_cast when not DEBUG?723 724 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);725 assert(pinfo); // this should not fail!!726 727 switch(pinfo->getFormat()) {728 case AmdtpPortInfo::E_MBLA:729 if(encodeSilencePortToMBLAEvents(static_cast<AmdtpAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) {730 debugWarning("Could not encode port %s to MBLA events",(*it)->getName().c_str());731 problem=1;732 }733 break;734 case AmdtpPortInfo::E_SPDIF: // still unimplemented735 break;736 default: // ignore737 break;738 }739 }740 return problem;741 742 }743 744 /**745 * @brief decode a packet for the packet-based ports746 *747 * @param data Packet data748 * @param nevents number of events in data (including events of other ports & port types)749 * @param dbc DataBlockCount value for this packet750 * @return true if all successfull751 */752 bool AmdtpTransmitStreamProcessor::encodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc)753 {754 bool ok=true;755 quadlet_t byte;756 757 quadlet_t *target_event=NULL;758 unsigned int j;759 760 for ( PortVectorIterator it = m_PacketPorts.begin();761 it != m_PacketPorts.end();762 ++it )763 {764 765 #ifdef DEBUG766 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);767 assert(pinfo); // this should not fail!!768 769 // the only packet type of events for AMDTP is MIDI in mbla770 assert(pinfo->getFormat()==AmdtpPortInfo::E_Midi);771 #endif772 773 AmdtpMidiPort *mp=static_cast<AmdtpMidiPort *>(*it);774 775 // we encode this directly (no function call) due to the high frequency776 /* idea:777 spec says: current_midi_port=(dbc+j)%8;778 => if we start at (dbc+stream->location-1)%8,779 we'll start at the right event for the midi port.780 => if we increment j with 8, we stay at the right event.781 */782 // FIXME: as we know in advance how big a packet is (syt_interval) we can783 // predict how much loops will be present here784 // first prefill the buffer with NO_DATA's on all time muxed channels785 786 for(j = (dbc & 0x07)+mp->getLocation(); j < nevents; j += 8) {787 788 quadlet_t tmpval;789 790 target_event=(quadlet_t *)(data + ((j * m_dimension) + mp->getPosition()));791 792 if(mp->canRead()) { // we can send a byte793 mp->readEvent(&byte);794 byte &= 0xFF;795 tmpval=htonl(796 IEC61883_AM824_SET_LABEL((byte)<<16,797 IEC61883_AM824_LABEL_MIDI_1X));798 799 debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, "MIDI port %s, pos=%d, loc=%d, dbc=%d, nevents=%d, dim=%d\n",800 mp->getName().c_str(), mp->getPosition(), mp->getLocation(), dbc, nevents, m_dimension);801 debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, "base=%p, target=%p, value=%08X\n",802 data, target_event, tmpval);803 804 } else {805 // can't send a byte, either because there is no byte,806 // or because this would exceed the maximum rate807 tmpval=htonl(808 IEC61883_AM824_SET_LABEL(0,IEC61883_AM824_LABEL_MIDI_NO_DATA));809 }810 811 *target_event=tmpval;812 }813 814 }815 816 return ok;817 }818 819 820 int AmdtpTransmitStreamProcessor::encodePortToMBLAEvents(AmdtpAudioPort *p, quadlet_t *data,821 unsigned int offset, unsigned int nevents)822 {823 unsigned int j=0;824 825 quadlet_t *target_event;826 827 target_event=(quadlet_t *)(data + p->getPosition());828 829 switch(p->getDataType()) {830 default:831 case Port::E_Int24:832 {833 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());834 835 assert(nevents + offset <= p->getBufferSize());836 837 buffer+=offset;838 839 for(j = 0; j < nevents; j += 1) { // decode max nsamples840 *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);841 buffer++;842 target_event += m_dimension;843 }844 }845 break;846 case Port::E_Float:847 {848 const float multiplier = (float)(0x7FFFFF00);849 float *buffer=(float *)(p->getBufferAddress());850 851 assert(nevents + offset <= p->getBufferSize());852 853 buffer+=offset;854 855 for(j = 0; j < nevents; j += 1) { // decode max nsamples856 857 // don't care for overflow858 float v = *buffer * multiplier; // v: -231 .. 231859 unsigned int tmp = ((int)v);860 *target_event = htonl((tmp >> 8) | 0x40000000);861 862 buffer++;863 target_event += m_dimension;864 }865 }866 break;867 }868 869 return 0;870 }871 int AmdtpTransmitStreamProcessor::encodeSilencePortToMBLAEvents(AmdtpAudioPort *p, quadlet_t *data,872 unsigned int offset, unsigned int nevents)873 {874 unsigned int j=0;875 876 quadlet_t *target_event;877 878 target_event=(quadlet_t *)(data + p->getPosition());879 880 switch(p->getDataType()) {881 default:882 case Port::E_Int24:883 case Port::E_Float:884 {885 for(j = 0; j < nevents; j += 1) { // decode max nsamples886 *target_event = htonl(0x40000000);887 target_event += m_dimension;888 }889 }890 break;891 }892 893 return 0;894 }895 896 41 /* --------------------- RECEIVE ----------------------- */ 897 42 898 43 AmdtpReceiveStreamProcessor::AmdtpReceiveStreamProcessor(int port, int framerate, int dimension) 899 : ReceiveStreamProcessor(port, framerate), m_dimension(dimension), m_last_timestamp(0), m_last_timestamp2(0) 44 : ReceiveStreamProcessor(port, framerate) 45 , m_dimension(dimension) 46 , m_last_timestamp(0) 47 , m_last_timestamp2(0) 48 , m_dropped(0) 900 49 {} 901 50 … … 918 67 919 68 enum raw1394_iso_disposition retval=RAW1394_ISO_OK; 69 70 int dropped_cycles=diffCycles(cycle, m_last_cycle) - 1; 71 if (dropped_cycles < 0) debugWarning("(%p) dropped < 1 (%d)\n", this, dropped_cycles); 72 else m_dropped += dropped_cycles; 73 if (dropped_cycles > 0) debugWarning("(%p) dropped %d packets on cycle %u\n", this, dropped_cycles, cycle); 74 920 75 m_last_cycle=cycle; 921 76 … … 925 80 #ifdef DEBUG 926 81 if(dropped>0) { 927 debugWarning(" Dropped %d packets on cycle %d\n",dropped, cycle);82 debugWarning("(%p) Dropped %d packets on cycle %d\n", this, dropped, cycle); 928 83 } 929 84 … … 956 111 m_last_timestamp2=m_last_timestamp; 957 112 113 uint64_t nowX = m_handler->getCycleTimer(); 958 114 //=> convert the SYT to a full timestamp in ticks 959 115 m_last_timestamp=sytRecvToFullTicks((uint32_t)ntohs(packet->syt), 960 cycle, m_handler->getCycleTimer()); 116 cycle, nowX); 117 118 int64_t diffx = diffTicks(m_last_timestamp, m_last_timestamp2); 119 if (abs(diffx) > m_syt_interval * m_data_buffer->getRate() * 1.1) { 120 uint32_t now=m_handler->getCycleTimer(); 121 uint32_t syt = (uint32_t)ntohs(packet->syt); 122 uint32_t now_ticks=CYCLE_TIMER_TO_TICKS(now); 123 124 debugOutput(DEBUG_LEVEL_VERBOSE, "diff=%06lld TS=%011llu TS2=%011llu\n", 125 diffx, m_last_timestamp, m_last_timestamp2); 126 debugOutput(DEBUG_LEVEL_VERBOSE, "[1] cy=%04d dropped=%05llu syt=%04llX NOW=%08llX => TS=%011llu\n", 127 m_last_good_cycle, m_last_dropped, m_last_syt, m_last_now, m_last_timestamp2); 128 debugOutput(DEBUG_LEVEL_VERBOSE, "[2] cy=%04d dropped=%05d syt=%04X NOW=%08llX => TS=%011llu\n", 129 cycle, dropped_cycles, ntohs(packet->syt), nowX, m_last_timestamp); 130 131 uint32_t test_ts=sytRecvToFullTicks(syt, cycle, now); 132 133 debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: SYT=%08X, CY=%04d OFF=%04d\n", 134 cycle, syt, CYCLE_TIMER_GET_CYCLES(syt), CYCLE_TIMER_GET_OFFSET(syt) 135 ); 136 debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: NOW=%011lu, SEC=%03u CY=%04u OFF=%04u\n", 137 cycle, now_ticks, CYCLE_TIMER_GET_SECS(now), CYCLE_TIMER_GET_CYCLES(now), CYCLE_TIMER_GET_OFFSET(now) 138 ); 139 debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: TSS=%011lu, SEC=%03u CY=%04u OFF=%04u\n", 140 cycle, test_ts, TICKS_TO_SECS(test_ts), TICKS_TO_CYCLES(test_ts), TICKS_TO_OFFSET(test_ts) 141 ); 142 143 int64_t diff_ts = diffTicks(now_ticks, test_ts); 144 debugOutput(DEBUG_LEVEL_VERBOSE, "DIFF : TCK=%011lld, SEC=%03llu CY=%04llu OFF=%04llu\n", 145 diff_ts, 146 TICKS_TO_SECS((uint64_t)diff_ts), 147 TICKS_TO_CYCLES((uint64_t)diff_ts), 148 TICKS_TO_OFFSET((uint64_t)diff_ts) 149 ); 150 } 151 m_last_syt = ntohs(packet->syt); 152 m_last_now = nowX; 153 m_last_good_cycle = cycle; 154 m_last_dropped = dropped_cycles; 961 155 962 156 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "RECV: CY=%04u TS=%011llu\n", … … 977 171 debugOutput(DEBUG_LEVEL_VERBOSE,"Receive StreamProcessor %p started running at %d\n", this, cycle); 978 172 m_running=true; 979 } 980 173 m_data_buffer->setBufferTailTimestamp(m_last_timestamp); 174 // we don't want this first sample to be written 175 return RAW1394_ISO_OK; 176 } 177 178 // if we are not running yet, there is nothing more to do 179 if(!m_running) { 180 return RAW1394_ISO_OK; 181 } 981 182 #ifdef DEBUG_OFF 982 183 if((cycle % 1000) == 0) { … … 1008 209 //=> process the packet 1009 210 // add the data payload to the ringbuffer 211 212 if(dropped_cycles) { 213 debugWarning("(%p) Correcting timestamp for dropped cycles, discarding packet...\n", this); 214 m_data_buffer->setBufferTailTimestamp(m_last_timestamp); 215 // we don't want this first sample to be written 216 return RAW1394_ISO_OK; 217 } 218 1010 219 if(m_data_buffer->writeFrames(nevents, (char *)(data+8), m_last_timestamp)) { 1011 220 retval=RAW1394_ISO_OK; … … 1105 314 1106 315 assert(m_data_buffer); 1107 m_data_buffer->setBufferSize(ringbuffer_size_frames );316 m_data_buffer->setBufferSize(ringbuffer_size_frames * 2); 1108 317 m_data_buffer->setEventSize(sizeof(quadlet_t)); 1109 318 m_data_buffer->setEventsPerFrame(m_dimension); … … 1214 423 m_PeriodStat.mark(m_data_buffer->getBufferFill()); 1215 424 425 #ifdef DEBUG 426 uint64_t ts_head; 427 signed int fc; 428 int32_t lag_ticks; 429 float lag_frames; 430 431 // in order to sync up multiple received streams, we should 432 // use the ts parameter. It specifies the time of the block's 433 // first sample. 434 435 ffado_timestamp_t ts_head_tmp; 436 m_data_buffer->getBufferHeadTimestamp(&ts_head_tmp, &fc); 437 ts_head=(uint64_t)ts_head_tmp; 438 lag_ticks=diffTicks(ts, ts_head); 439 float rate=m_data_buffer->getRate(); 440 441 assert(rate!=0.0); 442 443 lag_frames=(((float)lag_ticks)/rate); 444 445 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "stream (%p): drifts %6d ticks = %10.5f frames (rate=%10.5f), %lld, %llu, %d\n", 446 this, lag_ticks, lag_frames,rate, ts, ts_head, fc); 447 448 if (lag_frames>=1.0) { 449 // the stream lags 450 debugWarning( "stream (%p): lags with %6d ticks = %10.5f frames (rate=%10.5f), %lld, %llu, %d\n", 451 this, lag_ticks, lag_frames,rate, ts, ts_head, fc); 452 } else if (lag_frames<=-1.0) { 453 // the stream leads 454 debugWarning( "stream (%p): leads with %6d ticks = %10.5f frames (rate=%10.5f), %lld, %llu, %d\n", 455 this, lag_ticks, lag_frames,rate, ts, ts_head, fc); 456 } 457 #endif 1216 458 // ask the buffer to process nbframes of frames 1217 459 // using it's registered client's processReadBlock(), branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.h
r709 r712 22 22 */ 23 23 24 #ifndef __FFADO_AMDTP STREAMPROCESSOR__25 #define __FFADO_AMDTP STREAMPROCESSOR__24 #ifndef __FFADO_AMDTPRECEIVESTREAMPROCESSOR__ 25 #define __FFADO_AMDTPRECEIVESTREAMPROCESSOR__ 26 26 27 27 /** … … 57 57 class AmdtpAudioPort; 58 58 class AmdtpMidiPort; 59 class AmdtpReceiveStreamProcessor;60 61 /*!62 \brief The Base Class for an AMDTP transmit stream processor63 64 This class implements a TransmitStreamProcessor that multiplexes Ports65 into AMDTP streams.66 67 */68 class AmdtpTransmitStreamProcessor69 : public TransmitStreamProcessor70 {71 72 public:73 /**74 * Create a AMDTP transmit StreamProcessor75 * @param port 1394 port76 * @param framerate frame rate77 * @param dimension number of substreams in the ISO stream78 * (midi-muxed is only one stream)79 */80 AmdtpTransmitStreamProcessor(int port, int framerate, int dimension);81 virtual ~AmdtpTransmitStreamProcessor() {};82 83 enum raw1394_iso_disposition84 getPacket(unsigned char *data, unsigned int *length,85 unsigned char *tag, unsigned char *sy,86 int cycle, unsigned int dropped, unsigned int max_length);87 88 bool init();89 bool reset();90 bool prepare();91 92 bool prepareForStop();93 bool prepareForStart();94 95 bool prepareForEnable(uint64_t time_to_enable_at);96 97 bool putFrames(unsigned int nbframes, int64_t ts); ///< transfer the buffer contents from the client98 bool putFramesDry(unsigned int nbframes, int64_t ts);99 100 // We have 1 period of samples = m_period101 // this period takes m_period/m_framerate seconds of time102 // during this time, 8000 packets are sent103 // unsigned int getPacketsPerPeriod() {return (m_period*8000)/m_framerate;};104 105 // however, if we only count the number of used packets106 // it is m_period / m_syt_interval107 unsigned int getPacketsPerPeriod() {return (m_period)/m_syt_interval;};108 109 unsigned int getMaxPacketSize() {return 4 * (2 + m_syt_interval * m_dimension);};110 111 protected:112 bool processWriteBlock(char *data, unsigned int nevents, unsigned int offset);113 114 struct iec61883_cip m_cip_status;115 116 int m_dimension;117 unsigned int m_syt_interval;118 119 int m_fdf;120 121 bool prefill();122 123 unsigned int fillNoDataPacketHeader(struct iec61883_packet *packet, unsigned int* length);124 unsigned int fillDataPacketHeader(struct iec61883_packet *packet, unsigned int* length, uint32_t ts);125 126 127 bool transferSilence(unsigned int size);128 129 int transmitBlock(char *data, unsigned int nevents,130 unsigned int offset);131 132 bool encodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc);133 int encodePortToMBLAEvents(AmdtpAudioPort *, quadlet_t *data,134 unsigned int offset, unsigned int nevents);135 136 int transmitSilenceBlock(char *data, unsigned int nevents,137 unsigned int offset);138 int encodeSilencePortToMBLAEvents(AmdtpAudioPort *, quadlet_t *data,139 unsigned int offset, unsigned int nevents);140 void updatePreparedState();141 142 unsigned long m_last_timestamp;143 144 unsigned int m_dbc;145 146 unsigned int m_ringbuffer_size_frames;147 };148 59 /*! 149 60 \brief The Base Class for an AMDTP receive stream processor … … 207 118 unsigned int m_syt_interval; 208 119 120 uint64_t m_dropped; /// FIXME:debug 121 uint64_t m_last_dropped; /// FIXME:debug 122 uint64_t m_last_syt; /// FIXME:debug 123 uint64_t m_last_now; /// FIXME:debug 124 int m_last_good_cycle; /// FIXME:debug 209 125 uint64_t m_last_timestamp; /// last timestamp (in ticks) 210 126 uint64_t m_last_timestamp2; /// last timestamp (in ticks) … … 215 131 } // end of namespace Streaming 216 132 217 #endif /* __FFADO_AMDTP STREAMPROCESSOR__ */133 #endif /* __FFADO_AMDTPRECEIVESTREAMPROCESSOR__ */ 218 134 branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpSlaveStreamProcessor.h
r705 r712 28 28 * This class implements IEC61883-6 / AM824 / AMDTP based streaming 29 29 */ 30 #include "AmdtpStreamProcessor.h" 30 #include "AmdtpReceiveStreamProcessor.h" 31 #include "AmdtpTransmitStreamProcessor.h" 31 32 #include "../util/cip.h" 32 33 branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp
r709 r712 22 22 */ 23 23 24 #include "Amdtp StreamProcessor.h"24 #include "AmdtpTransmitStreamProcessor.h" 25 25 #include "AmdtpPort.h" 26 26 … … 78 78 debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE,"Xmit handler for cycle %d, (running=%d)\n", 79 79 cycle, m_running); 80 81 if (addCycles(m_last_cycle, 1) != cycle) { 82 debugWarning("(%p) Dropped %d packets on cycle %d\n", diffCycles(cycle,m_last_cycle)-1, cycle); 83 } 80 84 81 85 m_last_cycle=cycle; … … 159 163 // given by TRANSMIT_TRANSFER_DELAY (in ticks), but we can send 160 164 // packets early if we want to. (not completely according to spec) 161 const int max_cycles_to_transmit_early = 1;165 const int max_cycles_to_transmit_early = 5; 162 166 163 167 if( !m_running || !m_data_buffer->isEnabled() ) { … … 487 491 488 492 assert(m_data_buffer); 489 m_data_buffer->setBufferSize(m_ringbuffer_size_frames );493 m_data_buffer->setBufferSize(m_ringbuffer_size_frames * 2); 490 494 m_data_buffer->setEventSize(sizeof(quadlet_t)); 491 495 m_data_buffer->setEventsPerFrame(m_dimension); … … 622 626 bool AmdtpTransmitStreamProcessor::transferSilence(unsigned int nframes) { 623 627 bool retval; 624 628 signed int fc; 629 ffado_timestamp_t ts_tail_tmp; 630 uint64_t ts_tail; 631 632 // prepare a buffer of silence 625 633 char *dummybuffer=(char *)calloc(sizeof(quadlet_t),nframes*m_dimension); 626 627 634 transmitSilenceBlock(dummybuffer, nframes, 0); 628 635 636 637 m_data_buffer->getBufferTailTimestamp(&ts_tail_tmp, &fc); 638 if (fc != 0) { 639 debugWarning("Prefilling a buffer that already contains %d frames\n", fc); 640 } 641 642 ts_tail = (uint64_t)ts_tail_tmp; 643 // modify the timestamp such that it makes sense 644 ts_tail = addTicks(ts_tail, (uint64_t)(nframes * getTicksPerFrame())); 629 645 // add the silence data to the ringbuffer 630 if(m_data_buffer->writeFrames(nframes, dummybuffer, 0)) {646 if(m_data_buffer->writeFrames(nframes, dummybuffer, ts_tail)) { 631 647 retval=true; 632 648 } else { … … 664 680 retval=true; 665 681 } else { 666 debugWarning("Could not write to event buffer\n");682 debugWarning("Could not write %u events to event buffer\n", nbframes); 667 683 retval=false; 668 684 } … … 894 910 } 895 911 896 /* --------------------- RECEIVE ----------------------- */897 898 AmdtpReceiveStreamProcessor::AmdtpReceiveStreamProcessor(int port, int framerate, int dimension)899 : ReceiveStreamProcessor(port, framerate), m_dimension(dimension), m_last_timestamp(0), m_last_timestamp2(0)900 {}901 902 bool AmdtpReceiveStreamProcessor::init() {903 904 // call the parent init905 // this has to be done before allocating the buffers,906 // because this sets the buffersizes from the processormanager907 if(!ReceiveStreamProcessor::init()) {908 debugFatal("Could not do base class init (%d)\n",this);909 return false;910 }911 return true;912 }913 914 enum raw1394_iso_disposition915 AmdtpReceiveStreamProcessor::putPacket(unsigned char *data, unsigned int length,916 unsigned char channel, unsigned char tag, unsigned char sy,917 unsigned int cycle, unsigned int dropped) {918 919 enum raw1394_iso_disposition retval=RAW1394_ISO_OK;920 m_last_cycle=cycle;921 922 struct iec61883_packet *packet = (struct iec61883_packet *) data;923 assert(packet);924 925 #ifdef DEBUG926 if(dropped>0) {927 debugWarning("Dropped %d packets on cycle %d\n",dropped, cycle);928 }929 930 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"ch%2u: CY=%4u, SYT=%08X (%4ucy + %04uticks) (running=%d)\n",931 channel, cycle, ntohs(packet->syt),932 CYCLE_TIMER_GET_CYCLES(ntohs(packet->syt)), CYCLE_TIMER_GET_OFFSET(ntohs(packet->syt)),933 m_running);934 935 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,936 "RCV: CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d\n",937 channel, packet->fdf,938 packet->syt,939 packet->dbs,940 packet->dbc,941 packet->fmt,942 length);943 944 #endif945 946 // check if this is a valid packet947 if((packet->syt != 0xFFFF)948 && (packet->fdf != 0xFF)949 && (packet->fmt == 0x10)950 && (packet->dbs>0)951 && (length>=2*sizeof(quadlet_t))) {952 953 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;954 955 //=> store the previous timestamp956 m_last_timestamp2=m_last_timestamp;957 958 //=> convert the SYT to a full timestamp in ticks959 m_last_timestamp=sytRecvToFullTicks((uint32_t)ntohs(packet->syt),960 cycle, m_handler->getCycleTimer());961 962 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "RECV: CY=%04u TS=%011llu\n",963 cycle, m_last_timestamp);964 965 // we have to keep in mind that there are also966 // some packets buffered by the ISO layer,967 // at most x=m_handler->getWakeupInterval()968 // these contain at most x*syt_interval969 // frames, meaning that we might receive970 // this packet x*syt_interval*ticks_per_frame971 // later than expected (the real receive time)972 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"STMP: %lluticks | buff=%d, syt_interval=%d, tpf=%f\n",973 m_last_timestamp, m_handler->getWakeupInterval(),m_syt_interval,getTicksPerFrame());974 975 //=> signal that we're running (if we are)976 if(!m_running && nevents && m_last_timestamp2 && m_last_timestamp) {977 debugOutput(DEBUG_LEVEL_VERBOSE,"Receive StreamProcessor %p started running at %d\n", this, cycle);978 m_running=true;979 }980 981 #ifdef DEBUG_OFF982 if((cycle % 1000) == 0) {983 uint32_t now=m_handler->getCycleTimer();984 uint32_t syt = (uint32_t)ntohs(packet->syt);985 uint32_t now_ticks=CYCLE_TIMER_TO_TICKS(now);986 987 uint32_t test_ts=sytRecvToFullTicks(syt, cycle, now);988 989 debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: SYT=%08X, CY=%02d OFF=%04d\n",990 cycle, syt, CYCLE_TIMER_GET_CYCLES(syt), CYCLE_TIMER_GET_OFFSET(syt)991 );992 debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: NOW=%011lu, SEC=%03u CY=%02u OFF=%04u\n",993 cycle, now_ticks, CYCLE_TIMER_GET_SECS(now), CYCLE_TIMER_GET_CYCLES(now), CYCLE_TIMER_GET_OFFSET(now)994 );995 debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: TSS=%011lu, SEC=%03u CY=%02u OFF=%04u\n",996 cycle, test_ts, TICKS_TO_SECS(test_ts), TICKS_TO_CYCLES(test_ts), TICKS_TO_OFFSET(test_ts)997 );998 }999 #endif1000 1001 #ifdef DEBUG1002 // keep track of the lag1003 uint32_t now=m_handler->getCycleTimer();1004 int32_t diff = diffCycles( cycle, ((int)CYCLE_TIMER_GET_CYCLES(now)) );1005 m_PacketStat.mark(diff);1006 #endif1007 1008 //=> process the packet1009 // add the data payload to the ringbuffer1010 if(m_data_buffer->writeFrames(nevents, (char *)(data+8), m_last_timestamp)) {1011 retval=RAW1394_ISO_OK;1012 1013 // process all ports that should be handled on a per-packet base1014 // this is MIDI for AMDTP (due to the need of DBC)1015 if (!decodePacketPorts((quadlet_t *)(data+8), nevents, packet->dbc)) {1016 debugWarning("Problem decoding Packet Ports\n");1017 retval=RAW1394_ISO_DEFER;1018 }1019 1020 } else {1021 1022 // debugWarning("Receive buffer overrun (cycle %d, FC=%d, PC=%d)\n",1023 // cycle, m_data_buffer->getFrameCounter(), m_handler->getPacketCount());1024 1025 m_xruns++;1026 1027 retval=RAW1394_ISO_DEFER;1028 }1029 }1030 1031 return retval;1032 }1033 1034 void AmdtpReceiveStreamProcessor::dumpInfo() {1035 StreamProcessor::dumpInfo();1036 }1037 1038 bool AmdtpReceiveStreamProcessor::reset() {1039 1040 debugOutput( DEBUG_LEVEL_VERBOSE, "Resetting...\n");1041 1042 m_PeriodStat.reset();1043 m_PacketStat.reset();1044 m_WakeupStat.reset();1045 1046 m_data_buffer->setTickOffset(0);1047 1048 // reset all non-device specific stuff1049 // i.e. the iso stream and the associated ports1050 if(!ReceiveStreamProcessor::reset()) {1051 debugFatal("Could not do base class reset\n");1052 return false;1053 }1054 return true;1055 }1056 1057 bool AmdtpReceiveStreamProcessor::prepare() {1058 1059 m_PeriodStat.setName("RCV PERIOD");1060 m_PacketStat.setName("RCV PACKET");1061 m_WakeupStat.setName("RCV WAKEUP");1062 1063 debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this);1064 1065 // prepare all non-device specific stuff1066 // i.e. the iso stream and the associated ports1067 if(!ReceiveStreamProcessor::prepare()) {1068 debugFatal("Could not prepare base class\n");1069 return false;1070 }1071 1072 switch (m_framerate) {1073 case 32000:1074 m_syt_interval = 8;1075 break;1076 case 44100:1077 m_syt_interval = 8;1078 break;1079 default:1080 case 48000:1081 m_syt_interval = 8;1082 break;1083 case 88200:1084 m_syt_interval = 16;1085 break;1086 case 96000:1087 m_syt_interval = 16;1088 break;1089 case 176400:1090 m_syt_interval = 32;1091 break;1092 case 192000:1093 m_syt_interval = 32;1094 break;1095 }1096 1097 // prepare the framerate estimate1098 float ticks_per_frame = (TICKS_PER_SECOND*1.0) / ((float)m_framerate);1099 m_ticks_per_frame=ticks_per_frame;1100 1101 debugOutput(DEBUG_LEVEL_VERBOSE,"Initializing remote ticks/frame to %f\n",ticks_per_frame);1102 1103 // initialize internal buffer1104 unsigned int ringbuffer_size_frames=m_nb_buffers * m_period;1105 1106 assert(m_data_buffer);1107 m_data_buffer->setBufferSize(ringbuffer_size_frames);1108 m_data_buffer->setEventSize(sizeof(quadlet_t));1109 m_data_buffer->setEventsPerFrame(m_dimension);1110 1111 // the buffer is written every syt_interval1112 m_data_buffer->setUpdatePeriod(m_syt_interval);1113 m_data_buffer->setNominalRate(ticks_per_frame);1114 1115 m_data_buffer->setWrapValue(128L*TICKS_PER_SECOND);1116 1117 m_data_buffer->prepare();1118 1119 // set the parameters of ports we can:1120 // we want the audio ports to be period buffered,1121 // and the midi ports to be packet buffered1122 for ( PortVectorIterator it = m_Ports.begin();1123 it != m_Ports.end();1124 ++it )1125 {1126 debugOutput(DEBUG_LEVEL_VERBOSE, "Setting up port %s\n",(*it)->getName().c_str());1127 if(!(*it)->setBufferSize(m_period)) {1128 debugFatal("Could not set buffer size to %d\n",m_period);1129 return false;1130 }1131 1132 switch ((*it)->getPortType()) {1133 case Port::E_Audio:1134 if(!(*it)->setSignalType(Port::E_PeriodSignalled)) {1135 debugFatal("Could not set signal type to PeriodSignalling");1136 return false;1137 }1138 // buffertype and datatype are dependant on the API1139 debugWarning("---------------- ! Doing hardcoded dummy setup ! --------------\n");1140 // buffertype and datatype are dependant on the API1141 if(!(*it)->setBufferType(Port::E_PointerBuffer)) {1142 debugFatal("Could not set buffer type");1143 return false;1144 }1145 if(!(*it)->useExternalBuffer(true)) {1146 debugFatal("Could not set external buffer usage");1147 return false;1148 }1149 if(!(*it)->setDataType(Port::E_Float)) {1150 debugFatal("Could not set data type");1151 return false;1152 }1153 break;1154 case Port::E_Midi:1155 if(!(*it)->setSignalType(Port::E_PacketSignalled)) {1156 debugFatal("Could not set signal type to PacketSignalling");1157 return false;1158 }1159 // buffertype and datatype are dependant on the API1160 // buffertype and datatype are dependant on the API1161 debugWarning("---------------- ! Doing hardcoded test setup ! --------------\n");1162 // buffertype and datatype are dependant on the API1163 if(!(*it)->setBufferType(Port::E_RingBuffer)) {1164 debugFatal("Could not set buffer type");1165 return false;1166 }1167 if(!(*it)->setDataType(Port::E_MidiEvent)) {1168 debugFatal("Could not set data type");1169 return false;1170 }1171 break;1172 default:1173 debugWarning("Unsupported port type specified\n");1174 break;1175 }1176 }1177 1178 // the API specific settings of the ports should already be set,1179 // as this is called from the processorManager->prepare()1180 // so we can init the ports1181 if(!initPorts()) {1182 debugFatal("Could not initialize ports!\n");1183 return false;1184 }1185 1186 if(!preparePorts()) {1187 debugFatal("Could not initialize ports!\n");1188 return false;1189 }1190 1191 debugOutput( DEBUG_LEVEL_VERBOSE, "Prepared for:\n");1192 debugOutput( DEBUG_LEVEL_VERBOSE, " Samplerate: %d, DBS: %d, SYT: %d\n",1193 m_framerate,m_dimension,m_syt_interval);1194 debugOutput( DEBUG_LEVEL_VERBOSE, " PeriodSize: %d, NbBuffers: %d\n",1195 m_period,m_nb_buffers);1196 debugOutput( DEBUG_LEVEL_VERBOSE, " Port: %d, Channel: %d\n",1197 m_port,m_channel);1198 1199 return true;1200 1201 }1202 1203 bool AmdtpReceiveStreamProcessor::prepareForStart() {1204 disable();1205 return true;1206 }1207 1208 bool AmdtpReceiveStreamProcessor::prepareForStop() {1209 disable();1210 return true;1211 }1212 1213 bool AmdtpReceiveStreamProcessor::getFrames(unsigned int nbframes, int64_t ts) {1214 m_PeriodStat.mark(m_data_buffer->getBufferFill());1215 1216 // ask the buffer to process nbframes of frames1217 // using it's registered client's processReadBlock(),1218 // which should be ours1219 m_data_buffer->blockProcessReadFrames(nbframes);1220 1221 return true;1222 }1223 1224 bool AmdtpReceiveStreamProcessor::getFramesDry(unsigned int nbframes, int64_t ts) {1225 m_PeriodStat.mark(m_data_buffer->getBufferFill());1226 int frames_to_ditch=(int)(nbframes);1227 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "stream (%p): dry run %d frames (@ ts=%lld)\n",1228 this, frames_to_ditch, ts);1229 char dummy[m_data_buffer->getBytesPerFrame()]; // one frame of garbage1230 1231 while (frames_to_ditch--) {1232 m_data_buffer->readFrames(1, dummy);1233 }1234 return true;1235 }1236 1237 /**1238 * \brief write received events to the stream ringbuffers.1239 */1240 bool AmdtpReceiveStreamProcessor::processReadBlock(char *data,1241 unsigned int nevents, unsigned int offset)1242 {1243 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "(%p)->processReadBlock(%u, %u)\n",this,nevents,offset);1244 1245 bool no_problem=true;1246 1247 for ( PortVectorIterator it = m_PeriodPorts.begin();1248 it != m_PeriodPorts.end();1249 ++it )1250 {1251 1252 if((*it)->isDisabled()) {continue;};1253 1254 //FIXME: make this into a static_cast when not DEBUG?1255 1256 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);1257 assert(pinfo); // this should not fail!!1258 1259 switch(pinfo->getFormat()) {1260 case AmdtpPortInfo::E_MBLA:1261 if(decodeMBLAEventsToPort(static_cast<AmdtpAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) {1262 debugWarning("Could not decode packet MBLA to port %s",(*it)->getName().c_str());1263 no_problem=false;1264 }1265 break;1266 case AmdtpPortInfo::E_SPDIF: // still unimplemented1267 break;1268 /* for this processor, midi is a packet based port1269 case AmdtpPortInfo::E_Midi:1270 break;*/1271 default: // ignore1272 break;1273 }1274 }1275 return no_problem;1276 1277 }1278 1279 /**1280 * @brief decode a packet for the packet-based ports1281 *1282 * @param data Packet data1283 * @param nevents number of events in data (including events of other ports & port types)1284 * @param dbc DataBlockCount value for this packet1285 * @return true if all successfull1286 */1287 bool AmdtpReceiveStreamProcessor::decodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc)1288 {1289 bool ok=true;1290 1291 quadlet_t *target_event=NULL;1292 unsigned int j;1293 1294 for ( PortVectorIterator it = m_PacketPorts.begin();1295 it != m_PacketPorts.end();1296 ++it )1297 {1298 1299 #ifdef DEBUG1300 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);1301 assert(pinfo); // this should not fail!!1302 1303 // the only packet type of events for AMDTP is MIDI in mbla1304 assert(pinfo->getFormat()==AmdtpPortInfo::E_Midi);1305 #endif1306 AmdtpMidiPort *mp=static_cast<AmdtpMidiPort *>(*it);1307 1308 // we decode this directly (no function call) due to the high frequency1309 /* idea:1310 spec says: current_midi_port=(dbc+j)%8;1311 => if we start at (dbc+stream->location-1)%8,1312 we'll start at the right event for the midi port.1313 => if we increment j with 8, we stay at the right event.1314 */1315 // FIXME: as we know in advance how big a packet is (syt_interval) we can1316 // predict how much loops will be present here1317 for(j = (dbc & 0x07)+mp->getLocation(); j < nevents; j += 8) {1318 target_event=(quadlet_t *)(data + ((j * m_dimension) + mp->getPosition()));1319 quadlet_t sample_int=ntohl(*target_event);1320 // FIXME: this assumes that 2X and 3X speed isn't used,1321 // because only the 1X slot is put into the ringbuffer1322 if(IEC61883_AM824_GET_LABEL(sample_int) != IEC61883_AM824_LABEL_MIDI_NO_DATA) {1323 sample_int=(sample_int >> 16) & 0x000000FF;1324 if(!mp->writeEvent(&sample_int)) {1325 debugWarning("Packet port events lost\n");1326 ok=false;1327 }1328 }1329 }1330 1331 }1332 1333 return ok;1334 }1335 1336 int AmdtpReceiveStreamProcessor::decodeMBLAEventsToPort(AmdtpAudioPort *p, quadlet_t *data,1337 unsigned int offset, unsigned int nevents)1338 {1339 unsigned int j=0;1340 1341 // printf("****************\n");1342 // hexDumpQuadlets(data,m_dimension*4);1343 // printf("****************\n");1344 1345 quadlet_t *target_event;1346 1347 target_event=(quadlet_t *)(data + p->getPosition());1348 1349 switch(p->getDataType()) {1350 default:1351 case Port::E_Int24:1352 {1353 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());1354 1355 assert(nevents + offset <= p->getBufferSize());1356 1357 buffer+=offset;1358 1359 for(j = 0; j < nevents; j += 1) { // decode max nsamples1360 *(buffer)=(ntohl((*target_event) ) & 0x00FFFFFF);1361 buffer++;1362 target_event+=m_dimension;1363 }1364 }1365 break;1366 case Port::E_Float:1367 {1368 const float multiplier = 1.0f / (float)(0x7FFFFF);1369 float *buffer=(float *)(p->getBufferAddress());1370 1371 assert(nevents + offset <= p->getBufferSize());1372 1373 buffer+=offset;1374 1375 for(j = 0; j < nevents; j += 1) { // decode max nsamples1376 1377 unsigned int v = ntohl(*target_event) & 0x00FFFFFF;1378 // sign-extend highest bit of 24-bit int1379 int tmp = (int)(v << 8) / 256;1380 1381 *buffer = tmp * multiplier;1382 1383 buffer++;1384 target_event+=m_dimension;1385 }1386 }1387 break;1388 }1389 1390 return 0;1391 }1392 1393 912 } // end of namespace Streaming branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.h
r709 r712 22 22 */ 23 23 24 #ifndef __FFADO_AMDTP STREAMPROCESSOR__25 #define __FFADO_AMDTP STREAMPROCESSOR__24 #ifndef __FFADO_AMDTPTRANSMITSTREAMPROCESSOR__ 25 #define __FFADO_AMDTPTRANSMITSTREAMPROCESSOR__ 26 26 27 27 /** … … 57 57 class AmdtpAudioPort; 58 58 class AmdtpMidiPort; 59 class AmdtpReceiveStreamProcessor;60 59 61 60 /*! … … 146 145 unsigned int m_ringbuffer_size_frames; 147 146 }; 148 /*!149 \brief The Base Class for an AMDTP receive stream processor150 151 This class implements a ReceiveStreamProcessor that demultiplexes152 AMDTP streams into Ports.153 154 */155 class AmdtpReceiveStreamProcessor156 : public ReceiveStreamProcessor157 {158 159 public:160 /**161 * Create a AMDTP receive StreamProcessor162 * @param port 1394 port163 * @param framerate frame rate164 * @param dimension number of substreams in the ISO stream165 * (midi-muxed is only one stream)166 */167 AmdtpReceiveStreamProcessor(int port, int framerate, int dimension);168 virtual ~AmdtpReceiveStreamProcessor() {};169 170 enum raw1394_iso_disposition putPacket(unsigned char *data, unsigned int length,171 unsigned char channel, unsigned char tag, unsigned char sy,172 unsigned int cycle, unsigned int dropped);173 174 175 bool init();176 bool reset();177 bool prepare();178 179 bool prepareForStop();180 bool prepareForStart();181 182 bool getFrames(unsigned int nbframes, int64_t ts); ///< transfer the buffer contents to the client183 bool getFramesDry(unsigned int nbframes, int64_t ts);184 185 // We have 1 period of samples = m_period186 // this period takes m_period/m_framerate seconds of time187 // during this time, 8000 packets are sent188 // unsigned int getPacketsPerPeriod() {return (m_period*8000)/m_framerate;};189 190 // however, if we only count the number of used packets191 // it is m_period / m_syt_interval192 unsigned int getPacketsPerPeriod() {return (m_period)/m_syt_interval;};193 194 unsigned int getMaxPacketSize() {return 4 * (2 + m_syt_interval * m_dimension);};195 196 void dumpInfo();197 protected:198 199 bool processReadBlock(char *data, unsigned int nevents, unsigned int offset);200 201 bool decodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc);202 203 int decodeMBLAEventsToPort(AmdtpAudioPort *, quadlet_t *data, unsigned int offset, unsigned int nevents);204 void updatePreparedState();205 206 int m_dimension;207 unsigned int m_syt_interval;208 209 uint64_t m_last_timestamp; /// last timestamp (in ticks)210 uint64_t m_last_timestamp2; /// last timestamp (in ticks)211 uint64_t m_last_timestamp_at_period_ticks;212 };213 214 147 215 148 } // end of namespace Streaming 216 149 217 #endif /* __FFADO_AMDTP STREAMPROCESSOR__ */150 #endif /* __FFADO_AMDTPTRANSMITSTREAMPROCESSOR__ */ 218 151 branches/ppalmers-streaming/src/libstreaming/generic/StreamProcessor.cpp
r709 r712 300 300 IsoStream::setVerboseLevel(l); 301 301 PortManager::setVerboseLevel(l); 302 m_data_buffer->setVerboseLevel(l); 302 303 } 303 304 branches/ppalmers-streaming/src/libstreaming/generic/StreamProcessor.h
r709 r712 107 107 virtual bool prepareForStart() {return true;}; 108 108 109 110 109 public: 111 110 Util::TimestampedBuffer *m_data_buffer; … … 234 233 235 234 int getLastCycle() {return m_last_cycle;}; 235 int getFrameRate() {return m_framerate;}; 236 236 237 237 int getBufferFill(); branches/ppalmers-streaming/src/libstreaming/StreamProcessorManager.cpp
r709 r712 341 341 m_SyncSource->setSyncDelay(max_of_min_delay); 342 342 343 343 debugOutput( DEBUG_LEVEL_VERBOSE, "Waiting for device to indicate clock sync lock...\n"); 344 //sleep(2); // FIXME: be smarter here 345 344 346 debugOutput( DEBUG_LEVEL_VERBOSE, "Resetting StreamProcessors...\n"); 345 347 // now we reset the frame counters … … 365 367 // m_SyncSource->m_data_buffer->setTransparent(false); 366 368 // debugShowBackLog(); 369 370 // m_SyncSource->setVerboseLevel(DEBUG_LEVEL_ULTRA_VERBOSE); 367 371 368 372 debugOutput( DEBUG_LEVEL_VERBOSE, "Waiting for sync...\n"); 369 373 // in order to obtain that, we wait for the first periods to be 370 374 // received. 371 int nb_sync_runs= 10;375 int nb_sync_runs=20; 372 376 while(nb_sync_runs--) { // or while not sync-ed? 373 377 waitForPeriod(); 374 375 378 // drop the frames for all receive SP's 376 379 dryRun(StreamProcessor::E_Receive); … … 378 381 // we don't have to dryrun for the xmit SP's since they 379 382 // are not sending data yet. 380 } 383 384 // sync the xmit SP's buffer head timestamps 385 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 386 it != m_TransmitProcessors.end(); 387 ++it ) { 388 // FIXME: encapsulate 389 (*it)->m_data_buffer->setBufferHeadTimestamp(m_time_of_transfer); 390 } 391 } 392 // m_SyncSource->setVerboseLevel(DEBUG_LEVEL_VERBOSE); 381 393 382 394 debugOutput( DEBUG_LEVEL_VERBOSE, " sync at TS=%011llu (%03us %04uc %04ut)...\n", … … 433 445 434 446 debugOutput( DEBUG_LEVEL_VERBOSE, "Running dry for a while...\n"); 435 #define MAX_DRYRUN_CYCLES 20447 #define MAX_DRYRUN_CYCLES 40 436 448 #define MIN_SUCCESSFUL_DRYRUN_CYCLES 4 437 449 // run some cycles 'dry' such that everything can stabilize … … 442 454 443 455 waitForPeriod(); 456 457 if (dryRun()) { 458 nb_succesful_cycles++; 459 } else { 460 debugOutput( DEBUG_LEVEL_VERBOSE, " This dry-run was not xrun free...\n" ); 461 resetXrunCounters(); 462 // reset the transmit SP's such that there is no issue with accumulating buffers 463 // FIXME: what about receive SP's 464 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 465 it != m_TransmitProcessors.end(); 466 ++it ) { 467 // FIXME: encapsulate 468 (*it)->reset(); //CHECK!!! 469 (*it)->m_data_buffer->setBufferHeadTimestamp(m_time_of_transfer); 470 } 471 472 nb_succesful_cycles = 0; 473 // FIXME: xruns can screw up the framecounter accounting. do something more sane here 474 } 475 nb_dryrun_cycles_left--; 476 } 477 478 if(nb_dryrun_cycles_left == 0) { 479 debugOutput( DEBUG_LEVEL_VERBOSE, " max # dry-run cycles achieved without steady-state...\n" ); 480 return false; 481 } 482 debugOutput( DEBUG_LEVEL_VERBOSE, " dry-run resulted in steady-state...\n" ); 483 484 // now we should clear the xrun flags 485 resetXrunCounters(); 486 487 /* debugOutput( DEBUG_LEVEL_VERBOSE, "Aligning streams...\n"); 488 // run some cycles 'dry' such that everything can stabilize 489 nb_dryrun_cycles_left = MAX_DRYRUN_CYCLES; 490 nb_succesful_cycles = 0; 491 while(nb_dryrun_cycles_left > 0 && 492 nb_succesful_cycles < MIN_SUCCESSFUL_DRYRUN_CYCLES ) { 493 494 waitForPeriod(); 495 496 // align the received streams 497 int64_t sp_lag; 498 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 499 it != m_ReceiveProcessors.end(); 500 ++it ) { 501 uint64_t ts_sp=(*it)->getTimeAtPeriod(); 502 uint64_t ts_sync=m_SyncSource->getTimeAtPeriod(); 503 504 sp_lag = diffTicks(ts_sp, ts_sync); 505 debugOutput( DEBUG_LEVEL_VERBOSE, " SP(%p) TS=%011llu - TS=%011llu = %04lld\n", 506 (*it), ts_sp, ts_sync, sp_lag); 507 // sync the other receive SP's to the sync source 508 // if((*it) != m_SyncSource) { 509 // if(!(*it)->m_data_buffer->syncCorrectLag(sp_lag)) { 510 // debugOutput(DEBUG_LEVEL_VERBOSE,"could not syncCorrectLag(%11lld) for stream processor (%p)\n", 511 // sp_lag, *it); 512 // } 513 // } 514 } 515 444 516 445 517 if (dryRun()) { … … 455 527 456 528 if(nb_dryrun_cycles_left == 0) { 457 debugOutput( DEBUG_LEVEL_VERBOSE, " max # dry-run cycles achieved without steady-state...\n" );458 return false; 459 } 460 debugOutput( DEBUG_LEVEL_VERBOSE, " dry-run resulted in steady-state...\n" );461 529 debugOutput( DEBUG_LEVEL_VERBOSE, " max # dry-run cycles achieved without aligned steady-state...\n" ); 530 return false; 531 } 532 debugOutput( DEBUG_LEVEL_VERBOSE, " dry-run resulted in aligned steady-state...\n" );*/ 533 462 534 // now we should clear the xrun flags 463 535 resetXrunCounters(); 464 465 536 // and off we go 466 537 return true; … … 913 984 // NOTE: before waitForPeriod() is called again, both the transmit 914 985 // and the receive processors should have done their transfer. 915 m_time_of_transfer =m_SyncSource->getTimeAtPeriod();986 m_time_of_transfer = m_SyncSource->getTimeAtPeriod(); 916 987 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "transfer at %llu ticks...\n", 917 988 m_time_of_transfer); branches/ppalmers-streaming/src/libstreaming/util/cycletimer.h
r707 r712 156 156 return x; 157 157 158 } 159 160 /** 161 * @brief Computes the sum of two cycle values 162 * 163 * This function computes a sum between cycles 164 * such that it respects wrapping (at 8000 cycles). 165 * 166 * The passed arguments are assumed to be valid cycle numbers, 167 * i.e. they should be wrapped at 8000 cycles 168 * 169 * See addTicks 170 * 171 * @param x First cycle value 172 * @param y Second cycle value 173 * @return the sum x+y, wrapped 174 */ 175 static inline unsigned int addCycles(unsigned int x, unsigned int y) { 176 unsigned int sum = x + y; 177 #ifdef DEBUG 178 if (x >= CYCLES_PER_SECOND || y >= CYCLES_PER_SECOND ) { 179 debugWarning("At least one argument not wrapped correctly: x=%u, y=%u\n",x,y); 180 } 181 #endif 182 183 // since both x and y are < CYCLES_PER_SECOND this should be enough to unwrap 184 if (sum > CYCLES_PER_SECOND) sum -= CYCLES_PER_SECOND; 185 return sum; 158 186 } 159 187 branches/ppalmers-streaming/src/libutil/TimestampedBuffer.cpp
r707 r712 152 152 debugWarning("(%p) rate (%10.5f) more that 10%% off nominal (rate=%10.5f, diff="TIMESTAMP_FORMAT_SPEC", update_period=%d)\n", 153 153 this, rate,m_nominal_rate,diff, m_update_period); 154 dumpInfo();154 //dumpInfo(); 155 155 return m_nominal_rate; 156 156 } else { … … 403 403 } else { 404 404 // add the data payload to the ringbuffer 405 if (ffado_ringbuffer_write(m_event_buffer,data,write_size) < write_size) 405 size_t written = ffado_ringbuffer_write(m_event_buffer, data, write_size); 406 if (written < write_size) 406 407 { 408 debugWarning("ringbuffer full, %u, %u\n", write_size, written); 407 409 return false; 408 410 } … … 710 712 EXIT_CRITICAL_SECTION; 711 713 712 debugOutput(DEBUG_LEVEL_VER Y_VERBOSE, "for (%p) to "714 debugOutput(DEBUG_LEVEL_VERBOSE, "for (%p) to " 713 715 TIMESTAMP_FORMAT_SPEC" => "TIMESTAMP_FORMAT_SPEC", NTS=" 714 716 TIMESTAMP_FORMAT_SPEC", DLL2=%f, RATE=%f\n", … … 761 763 this, new_timestamp, ts, m_buffer_next_tail_timestamp, m_dll_e2, getRate()); 762 764 765 } 766 767 /** 768 * @brief Synchronize the buffer head to a specified timestamp 769 * 770 * Try to synchronize the buffer head to a specific timestamp. This 771 * can mean adding or removing samples to/from the buffer such that 772 * the buffer head aligns with the specified timestamp. The alignment 773 * is within ts +/- Tsample/2 774 * 775 * @param target the timestamp to align to 776 * @return true if alignment succeeded, false if not 777 */ 778 bool 779 TimestampedBuffer::syncBufferHeadToTimestamp(ffado_timestamp_t target) 780 { 781 uint64_t ts_head; 782 uint64_t ts_target=(uint64_t)target; 783 signed int fc; 784 int32_t lag_ticks; 785 float lag_frames; 786 787 ffado_timestamp_t ts_head_tmp; 788 getBufferHeadTimestamp(&ts_head_tmp, &fc); 789 ts_head=(uint64_t)ts_head_tmp; 790 // if target > ts_head then the wanted buffer head timestamp 791 // is later than the actual. This means that we (might) have to drop 792 // some frames. 793 lag_ticks=diffTicks(ts_target, ts_head); 794 float rate=getRate(); 795 796 assert(rate!=0.0); 797 798 lag_frames=(((float)lag_ticks)/rate); 799 800 debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): HEAD=%llu, TS=%llu, diff=%ld = %10.5f frames (rate=%10.5f)\n", 801 this, ts_head, ts_target, lag_ticks, lag_frames, rate); 802 803 if (lag_frames>=1.0) { 804 // the buffer head is too early 805 // ditch frames until the buffer head is on time 806 char dummy[getBytesPerFrame()]; // one frame of garbage 807 int frames_to_ditch=(int)roundf(lag_frames); 808 debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): ditching %d frames (@ ts=%lld)\n",this,frames_to_ditch,ts_target); 809 810 while (frames_to_ditch--) { 811 readFrames(1, dummy); 812 } 813 814 } else if (lag_frames<=-1.0) { 815 // the buffer head is too late 816 // add some padding frames 817 int frames_to_add=(int)roundf(lag_frames); 818 debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): adding %d frames (@ ts=%lld)\n",this,-frames_to_add,ts_target); 819 820 while (frames_to_add++) { 821 writeDummyFrame(); 822 } 823 } 824 getBufferHeadTimestamp(&ts_head_tmp, &fc); 825 ts_head=(uint64_t)ts_head_tmp; 826 debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): new HEAD=%llu, fc=%d, target=%llu, new diff=%lld\n", 827 this, ts_head, fc, ts_target, diffTicks(ts_target, ts_head)); 828 // FIXME: of course this doesn't always succeed 829 return true; 830 } 831 832 /** 833 * @brief Synchronize the buffer tail to a specified timestamp 834 * 835 * Try to synchronize the buffer tail to a specific timestamp. This 836 * can mean adding or removing samples to/from the buffer such that 837 * the buffer tail aligns with the specified timestamp. The alignment 838 * is within ts +/- Tsample/2 839 * 840 * @param target the timestamp to align to 841 * @return true if alignment succeeded, false if not 842 */ 843 bool 844 TimestampedBuffer::syncBufferTailToTimestamp(ffado_timestamp_t target) 845 { 846 uint64_t ts_tail; 847 uint64_t ts_target=(uint64_t)target; 848 signed int fc; 849 int32_t lag_ticks; 850 float lag_frames; 851 852 debugWarning("Untested\n"); 853 854 ffado_timestamp_t ts_tail_tmp; 855 getBufferTailTimestamp(&ts_tail_tmp, &fc); 856 ts_tail=(uint64_t)ts_tail_tmp; 857 // if target < ts_tail then the wanted buffer head timestamp 858 // is later than the actual. This means that we (might) have to drop 859 // some frames. 860 lag_ticks=diffTicks(ts_tail, ts_target); 861 float rate=getRate(); 862 863 assert(rate!=0.0); 864 865 lag_frames=(((float)lag_ticks)/rate); 866 867 debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): HEAD=%llu, TS=%llu, diff=%ld = %10.5f frames (rate=%10.5f)\n", 868 this, ts_tail, ts_target, lag_ticks, lag_frames, rate); 869 870 if (lag_frames>=1.0) { 871 // the buffer head is too early 872 // ditch frames until the buffer head is on time 873 char dummy[getBytesPerFrame()]; // one frame of garbage 874 int frames_to_ditch=(int)roundf(lag_frames); 875 debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): ditching %d frames (@ ts=%lld)\n",this,frames_to_ditch,ts_target); 876 877 while (frames_to_ditch--) { 878 readFrames(1, dummy); 879 } 880 881 } else if (lag_frames<=-1.0) { 882 // the buffer head is too late 883 // add some padding frames 884 int frames_to_add=(int)roundf(lag_frames); 885 debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): adding %d frames (@ ts=%lld)\n",this,-frames_to_add,ts_target); 886 887 while (frames_to_add++) { 888 writeDummyFrame(); 889 } 890 } 891 getBufferHeadTimestamp(&ts_tail_tmp, &fc); 892 ts_tail=(uint64_t)ts_tail_tmp; 893 debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): new HEAD=%llu, fc=%d, target=%llu, new diff=%lld\n", 894 this, ts_tail, fc, ts_target, diffTicks(ts_target, ts_tail)); 895 // FIXME: of course this doesn't always succeed 896 return true; 897 } 898 899 /** 900 * @brief correct lag 901 * 902 * Try to synchronize the buffer tail to a specific timestamp. This 903 * can mean adding or removing samples to/from the buffer such that 904 * the buffer tail aligns with the specified timestamp. The alignment 905 * is within ts +/- Tsample/2 906 * 907 * @param target the timestamp to align to 908 * @return true if alignment succeeded, false if not 909 */ 910 bool 911 TimestampedBuffer::syncCorrectLag(int64_t lag_ticks) 912 { 913 float lag_frames; 914 float rate=getRate(); 915 assert(rate!=0.0); 916 917 lag_frames=(((float)lag_ticks)/rate); 918 if (lag_frames >= 1.0) { 919 // the buffer head is too late 920 // add some padding frames 921 int frames_to_add=(int)roundf(lag_frames); 922 debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): adding %d frames\n",this,frames_to_add); 923 924 while (frames_to_add++) { 925 writeDummyFrame(); 926 } 927 } else if (lag_frames <= -1.0) { 928 // the buffer head is too early 929 // ditch frames until the buffer head is on time 930 char dummy[getBytesPerFrame()]; // one frame of garbage 931 int frames_to_ditch=(int)roundf(lag_frames); 932 debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): ditching %d frames\n",this,-frames_to_ditch); 933 934 while (frames_to_ditch--) { 935 readFrames(1, dummy); 936 } 937 } 938 return true; 763 939 } 764 940 … … 920 1096 // return; 921 1097 // } 922 923 // update the DLL 924 ENTER_CRITICAL_SECTION; 925 diff = ts-m_buffer_next_tail_timestamp; 926 EXIT_CRITICAL_SECTION; 1098 ffado_timestamp_t pred_buffer_next_tail_timestamp; 1099 if(nbframes == m_update_period) { 1100 pred_buffer_next_tail_timestamp = m_buffer_next_tail_timestamp; 1101 } else { 1102 debugOutput( DEBUG_LEVEL_VERBOSE, 1103 "Number of frames (%u) != update period (%u)\n", 1104 nbframes, m_update_period ); 1105 // calculate the predicted timestamp for nframes (instead of m_update_period) 1106 // after the previous update. 1107 float rel_step = ((float)nbframes)/((float)m_update_period); 1108 ENTER_CRITICAL_SECTION; // FIXME: do we need these? 1109 ffado_timestamp_t corrected_step = (m_buffer_next_tail_timestamp - m_buffer_tail_timestamp) * rel_step; 1110 pred_buffer_next_tail_timestamp = m_buffer_tail_timestamp + corrected_step; 1111 EXIT_CRITICAL_SECTION; 1112 1113 debugOutput( DEBUG_LEVEL_VERBOSE, 1114 "Updated ("TIMESTAMP_FORMAT_SPEC","TIMESTAMP_FORMAT_SPEC") to ("TIMESTAMP_FORMAT_SPEC","TIMESTAMP_FORMAT_SPEC")\n", 1115 m_buffer_tail_timestamp, m_buffer_next_tail_timestamp, 1116 m_buffer_tail_timestamp, pred_buffer_next_tail_timestamp); 1117 1118 } 1119 1120 // the difference between the given TS and the one predicted for this time instant 1121 // this is the error for the DLL 1122 diff = ts - pred_buffer_next_tail_timestamp; 927 1123 928 1124 // check whether the update is within the allowed bounds 929 const float max_deviation = ( 100.0/100.0); // maximal relative difference considered normal930 ffado_timestamp_t expected_difference=m_update_period* getRate();931 ffado_timestamp_t max_abs_diff = expected_difference * max_deviation;1125 const float max_deviation = (50.0/100.0); // maximal relative difference considered normal 1126 ffado_timestamp_t one_update_step = nbframes * getRate(); 1127 ffado_timestamp_t max_abs_diff = one_update_step * (1.0 + max_deviation); 932 1128 933 1129 if (diff > max_abs_diff) { 934 debugWarning("(%p) difference rather large (+): diff="TIMESTAMP_FORMAT_SPEC", expected="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n",935 this, diff, expected_difference, ts, m_buffer_next_tail_timestamp);1130 debugWarning("(%p) difference rather large (+): diff="TIMESTAMP_FORMAT_SPEC", max="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n", 1131 this, diff, max_abs_diff, ts, pred_buffer_next_tail_timestamp); 936 1132 // debugShowBackLogLines(40); 937 938 // we can limit the difference939 // we can't discard it because that would prevent us from tracking the samplerate940 diff = max_abs_diff;941 942 1133 } else if (diff < -max_abs_diff) { 943 debugWarning("(%p) difference rather large (-): diff="TIMESTAMP_FORMAT_SPEC", expected="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n",944 this, diff, expected_difference, ts, m_buffer_next_tail_timestamp);1134 debugWarning("(%p) difference rather large (-): diff="TIMESTAMP_FORMAT_SPEC", max="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n", 1135 this, diff, -max_abs_diff, ts, pred_buffer_next_tail_timestamp); 945 1136 // debugShowBackLogLines(40); 946 947 // we can limit the difference 948 // we can't discard it because that would prevent us from tracking the samplerate 949 diff = -max_abs_diff; 950 } 951 952 // idea to implement it for nbframes values that differ from m_update_period: 953 // diff = diff * nbframes/m_update_period 954 // m_buffer_next_tail_timestamp = m_buffer_tail_timestamp + diff 1137 } 955 1138 956 1139 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "(%p): diff="TIMESTAMP_FORMAT_SPEC" ", 957 1140 this, diff); 958 959 // the maximal difference we can allow (64secs)960 // const ffado_timestamp_t max=m_wrap_at/2;961 //962 // if(diff > max) {963 // diff -= m_wrap_at;964 // } else if (diff < -max) {965 // diff += m_wrap_at;966 // }967 1141 968 1142 double err=diff; … … 971 1145 diff, err); 972 1146 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "B: FC=%10u, TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC"\n", 973 m_framecounter, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);1147 m_framecounter, m_buffer_tail_timestamp, pred_buffer_next_tail_timestamp); 974 1148 975 1149 ENTER_CRITICAL_SECTION; 976 1150 m_framecounter += nbframes; 977 1151 978 m_buffer_tail_timestamp =m_buffer_next_tail_timestamp;979 m_buffer_next_tail_timestamp +=(ffado_timestamp_t)(m_dll_b * err + m_dll_e2);1152 m_buffer_tail_timestamp = pred_buffer_next_tail_timestamp; 1153 m_buffer_next_tail_timestamp = pred_buffer_next_tail_timestamp + (ffado_timestamp_t)(m_dll_b * err + m_dll_e2); 980 1154 // m_buffer_tail_timestamp=ts; 981 1155 // m_buffer_next_tail_timestamp += (ffado_timestamp_t)(m_dll_b * err + m_dll_e2); branches/ppalmers-streaming/src/libutil/TimestampedBuffer.h
r705 r712 133 133 void setBufferHeadTimestamp(ffado_timestamp_t new_timestamp); 134 134 135 // sync related, also drops or add frames when necessary 136 bool syncBufferHeadToTimestamp(ffado_timestamp_t ts); 137 bool syncBufferTailToTimestamp(ffado_timestamp_t ts); 138 bool syncCorrectLag(int64_t ts); 139 135 140 ffado_timestamp_t getTimestampFromTail(int nframes); 136 141 ffado_timestamp_t getTimestampFromHead(int nframes); branches/ppalmers-streaming/src/maudio/maudio_avdevice.h
r705 r712 32 32 #include "bebob/bebob_avdevice.h" 33 33 34 #include "libstreaming/amdtp/AmdtpStreamProcessor.h" 34 #include "libstreaming/amdtp/AmdtpReceiveStreamProcessor.h" 35 #include "libstreaming/amdtp/AmdtpTransmitStreamProcessor.h" 35 36 #include "libstreaming/amdtp/AmdtpPort.h" 36 37 #include "libstreaming/amdtp/AmdtpPortInfo.h" branches/ppalmers-streaming/src/SConscript
r705 r712 153 153 libstreaming/amdtp/AmdtpPort.cpp \ 154 154 libstreaming/amdtp/AmdtpPortInfo.cpp \ 155 libstreaming/amdtp/AmdtpStreamProcessor.cpp \ 155 libstreaming/amdtp/AmdtpReceiveStreamProcessor.cpp \ 156 libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp \ 156 157 ' ) 157 158