58 | | // If the cycles have wrapped, correct ts_sec so it represents when timestamp |
---|
59 | | // was received. The timestamps sent by the MOTU are always 1 or two cycles |
---|
60 | | // in advance of the cycle timer (reasons unknown at this stage). In addition, |
---|
61 | | // iso buffering can delay the arrival of packets for quite a number of cycles |
---|
62 | | // (have seen a delay >12 cycles). |
---|
63 | | // Every so often we also see sph wrapping ahead of ct_now, so deal with that |
---|
64 | | // too. |
---|
65 | | if (CYCLE_TIMER_GET_CYCLES(sph) > now_cycles + 1000) { |
---|
66 | | //debugOutput(DEBUG_LEVEL_VERBOSE, "now=%d, ct=%d\n", now_cycles, CYCLE_TIMER_GET_CYCLES(sph)); |
---|
67 | | if (ts_sec) |
---|
68 | | ts_sec--; |
---|
69 | | else |
---|
70 | | ts_sec = 127; |
---|
71 | | } else |
---|
72 | | if (now_cycles > CYCLE_TIMER_GET_CYCLES(sph) + 1000) { |
---|
73 | | //debugOutput(DEBUG_LEVEL_VERBOSE, "inverted wrap: now=%d, ct=%d\n", now_cycles, CYCLE_TIMER_GET_CYCLES(sph)); |
---|
74 | | if (ts_sec == 127) |
---|
75 | | ts_sec = 0; |
---|
76 | | else |
---|
77 | | ts_sec++; |
---|
78 | | } |
---|
79 | | return timestamp + ts_sec*TICKS_PER_SECOND; |
---|
| 58 | // If the cycles have wrapped, correct ts_sec so it represents when timestamp |
---|
| 59 | // was received. The timestamps sent by the MOTU are always 1 or two cycles |
---|
| 60 | // in advance of the cycle timer (reasons unknown at this stage). In addition, |
---|
| 61 | // iso buffering can delay the arrival of packets for quite a number of cycles |
---|
| 62 | // (have seen a delay >12 cycles). |
---|
| 63 | // Every so often we also see sph wrapping ahead of ct_now, so deal with that |
---|
| 64 | // too. |
---|
| 65 | if (CYCLE_TIMER_GET_CYCLES(sph) > now_cycles + 1000) { |
---|
| 66 | if (ts_sec) |
---|
| 67 | ts_sec--; |
---|
| 68 | else |
---|
| 69 | ts_sec = 127; |
---|
| 70 | } else |
---|
| 71 | if (now_cycles > CYCLE_TIMER_GET_CYCLES(sph) + 1000) { |
---|
| 72 | if (ts_sec == 127) |
---|
| 73 | ts_sec = 0; |
---|
| 74 | else |
---|
| 75 | ts_sec++; |
---|
| 76 | } |
---|
| 77 | return timestamp + ts_sec*TICKS_PER_SECOND; |
---|
201 | | ts_head = substractTicks((int64_t)ts_head, |
---|
202 | | (uint32_t)((float)n_events * m_SyncSource->m_data_buffer->getRate())); |
---|
203 | | |
---|
| 199 | // For the MOTU this subtraction doesn't seem necessary, and in general just makes it take |
---|
| 200 | // longer to achieve stable sync. |
---|
| 201 | // ts_head = substractTicks(ts_head, |
---|
| 202 | // (uint32_t)((float)n_events * m_SyncSource->m_data_buffer->getRate())); |
---|
| 203 | // ts_head = substractTicks(ts_head, |
---|
| 204 | // (uint32_t)(m_SyncSource->m_data_buffer->getRate())); |
---|
269 | | uint64_t cycle_timer=CYCLE_TIMER_TO_TICKS(ctr); |
---|
270 | | |
---|
271 | | // time until the packet is to be sent (if > 0: send packet) |
---|
272 | | //debugOutput(DEBUG_LEVEL_VERBOSE,"pre: timestamp=%lld, cycle_timer=%lld, adv=%lld, cdiff=%d\n", |
---|
273 | | // timestamp, cycle_timer,ticks_to_advance,cycle_diff); |
---|
274 | | int32_t until_next=diffTicks(timestamp, cycle_timer + ticks_to_advance); |
---|
275 | | //debugOutput(DEBUG_LEVEL_VERBOSE,"post\n"); |
---|
276 | | |
---|
277 | | until_next = (cycle >= TICKS_TO_CYCLES(timestamp))?-1:1; |
---|
| 261 | // uint64_t cycle_timer=CYCLE_TIMER_TO_TICKS(ctr); |
---|
| 262 | |
---|
| 263 | // time until the packet is to be sent (if <= 0: send packet) |
---|
| 264 | // For Amdtp this looked like |
---|
| 265 | // int32_t until_next=diffTicks(timestamp, cycle_timer + ticks_to_advance); |
---|
| 266 | // However, this didn't seem to work well with the MOTU's buffer structure. |
---|
| 267 | // For now we'll revert to the "send trigger" we used earlier since this |
---|
| 268 | // seems to work. |
---|
| 269 | int32_t until_next = (cycle >= TICKS_TO_CYCLES(timestamp))?-1:1; |
---|
297 | | #warning high-pitched sound protection removed! |
---|
298 | | // In the disabled state simply zero all data sent to the MOTU. If |
---|
299 | | // a stream of empty packets are sent once iso streaming is enabled |
---|
300 | | // the MOTU tends to emit high-pitched audio (approx 10 kHz) for |
---|
301 | | // some reason. This is not completely sufficient, however (zeroed |
---|
302 | | // packets must also be sent on iso closedown). |
---|
303 | | |
---|
304 | | // FIXME: Currently we simply send empty packets to the MOTU when |
---|
305 | | // the stream is disabled so the "m_disabled == 0" code is never |
---|
306 | | // executed. However, this may change in future so it's left in |
---|
307 | | // for the moment for reference. |
---|
308 | | // FIXME: Currently we don't read the buffer at all during closedown. |
---|
309 | | // We could (and silently junk the contents) if it turned out to be |
---|
310 | | // more helpful. |
---|
311 | | |
---|
312 | | //if (!m_is_disabled && m_running) |
---|
313 | | // return RAW1394_ISO_OK; |
---|
314 | | //else |
---|
321 | | if (m_data_buffer->readFrames(n_events, (char *)(data + 8))) { |
---|
322 | | |
---|
| 295 | // Only read frames from the tx buffer when we're not in the process of |
---|
| 296 | // stopping. When preparing for stop the buffer isn't necessarily being |
---|
| 297 | // replinished so it's possible to cause a buffer underflow during |
---|
| 298 | // shutdown if the buffer is read during this time. |
---|
| 299 | if (m_closedown_count!=-1 || m_data_buffer->readFrames(n_events, (char *)(data + 8))) { |
---|
| 300 | |
---|
| 301 | #if TESTTONE |
---|
| 302 | // FIXME: remove this hacked in 1 kHz test signal to |
---|
| 303 | // analog-1 when testing is complete. Note that the tone is |
---|
| 304 | // *never* added during closedown. |
---|
| 305 | if (m_closedown_count<0) { |
---|
| 306 | for (i=0; i<n_events; i++) { |
---|
| 307 | static signed int a_cx = 0; |
---|
| 308 | signed int val; |
---|
| 309 | val = (int)(0x7fffff*sin(1000.0*2.0*M_PI*(a_cx/24576000.0))); |
---|
| 310 | if ((a_cx+=512) >= 24576000) { |
---|
| 311 | a_cx -= 24576000; |
---|
| 312 | } |
---|
| 313 | *(data+8+i*m_event_size+16) = (val >> 16) & 0xff; |
---|
| 314 | *(data+8+i*m_event_size+17) = (val >> 8) & 0xff; |
---|
| 315 | *(data+8+i*m_event_size+18) = val & 0xff; |
---|
| 316 | } |
---|
| 317 | } |
---|
| 318 | #endif |
---|
344 | | // FIXME: if we choose to read the buffer even during closedown, |
---|
345 | | // here is where the data is silenced. |
---|
346 | | // if (m_closedown_count >= 0) |
---|
347 | | // memset(data+8, 0, read_size); |
---|
| 340 | // Zero out data if we're in closedown or startup |
---|
| 341 | if (m_closedown_count>=0 || m_startup_count>=0) { |
---|
| 342 | memset(data+8,0,n_events*m_event_size); |
---|
| 343 | } |
---|
| 344 | |
---|
| 345 | // Account for this packet's frames during startup / closedown. Note: |
---|
| 346 | // * m_startup_count: -1 = not in startup delay, >-1 = in startup delay. |
---|
| 347 | // * m_closedown_count: -1 = not in closedown mode, 0 = closedown |
---|
| 348 | // preparation now finished, >0 = closedown preparation in |
---|
| 349 | // progress. |
---|
361 | | #if 0 |
---|
362 | | if (i==0) { |
---|
363 | | debugOutput(DEBUG_LEVEL_VERBOSE," ts_frame=%8x (%3d:%04d:%04d)\n",ts_frame, |
---|
364 | | TICKS_TO_SECS(ts_frame), TICKS_TO_CYCLES(ts_frame), TICKS_TO_OFFSET(ts_frame)); |
---|
365 | | } |
---|
366 | | #endif |
---|
367 | | #if 0 |
---|
368 | | if (cycle<2) { |
---|
369 | | debugOutput(DEBUG_LEVEL_VERBOSE,"cycle %d: %d %d %d\n", |
---|
370 | | cycle, |
---|
371 | | TICKS_TO_SECS(ts_frame), |
---|
372 | | TICKS_TO_CYCLES(ts_frame), |
---|
373 | | TICKS_TO_OFFSET(ts_frame)); |
---|
374 | | } |
---|
375 | | #endif |
---|
376 | | #if TESTTONE |
---|
377 | | // FIXME: remove this hacked in 1 kHz test signal to |
---|
378 | | // analog-1 when testing is complete. Note that the tone is |
---|
379 | | // *never* added during closedown. |
---|
380 | | if (m_closedown_count<0) { |
---|
381 | | static signed int a_cx = 0; |
---|
382 | | signed int val; |
---|
383 | | val = (int)(0x7fffff*sin(1000.0*2.0*M_PI*(a_cx/24576000.0))); |
---|
384 | | if ((a_cx+=512) >= 24576000) { |
---|
385 | | a_cx -= 24576000; |
---|
386 | | } |
---|
387 | | *(data+8+i*m_event_size+16) = (val >> 16) & 0xff; |
---|
388 | | *(data+8+i*m_event_size+17) = (val >> 8) & 0xff; |
---|
389 | | *(data+8+i*m_event_size+18) = val & 0xff; |
---|
390 | | } |
---|
391 | | #endif |
---|
392 | | |
---|
416 | | // FIXME: port to new timestamp type |
---|
417 | | // debugWarning("Transmit buffer underrun (now %d, queue %d, target %d)\n", |
---|
418 | | // now_cycles, cycle, TICKS_TO_CYCLES(ts)); |
---|
| 387 | debugWarning("Transmit buffer underrun (now %d, queue %d, target %d)\n", |
---|
| 388 | now_cycles, cycle, TICKS_TO_CYCLES((int64_t)ts)); |
---|
1016 | | // NOTE by PP: timestamp based sync fixes this automagically by |
---|
1017 | | // enforcing that the roundtrip latency is constant: |
---|
1018 | | // Detect missed receive cycles |
---|
1019 | | // FIXME: it would be nice to advance the rx buffer by the amount of |
---|
1020 | | // frames missed. However, since the MOTU transmits more frames per |
---|
1021 | | // cycle than the average and "catches up" with periodic empty |
---|
1022 | | // cycles it's not trivial to work out precisely how many frames |
---|
1023 | | // were missed. Ultimately I think we need to do so if sync is to |
---|
1024 | | // be maintained across a transient receive failure. |
---|
1025 | | |
---|
1104 | | //=> convert the SYT to a full timestamp in ticks |
---|
1105 | | // m_last_timestamp=sytRecvToFullTicks((uint32_t)ntohl(*(quadlet_t *)(data+8)), |
---|
1106 | | // cycle, m_handler->getCycleTimer()); |
---|
1107 | | //*** |
---|
1108 | | // FIXME: it given that we later advance this to be the timestamp of the sample immediately following |
---|
1109 | | // this packet, it perhaps makes more sense to acquire the timestamp of the last frame in the packet. |
---|
1110 | | // Then it's just a matter of adding m_ticks_per_frame rather than frame_size times this. |
---|
1111 | | #if 0 |
---|
1112 | | uint32_t first_sph = ntohl(*(quadlet_t *)(data+8)); |
---|
1113 | | //uint32_t first_sph = ntohl(*(quadlet_t *)(data+8+(event_length*(n_events-1)))); |
---|
1114 | | // m_last_timestamp = ((first_sph & 0x1fff000)>>12)*3072 + (first_sph & 0xfff); |
---|
1115 | | // m_last_timestamp = CYCLE_TIMER_TO_TICKS(first_sph & 0x1ffffff); |
---|
1116 | | m_last_timestamp = sphRecvToFullTicks(first_sph, m_handler->getCycleTimer()); |
---|
1117 | | float frame_size=m_framerate<=48000?8:(m_framerate<=96000?16:32); |
---|
1118 | | uint64_t ts=addTicks(m_last_timestamp, (uint64_t)((frame_size-1) * m_ticks_per_frame)); |
---|
1119 | | m_last_timestamp = ts; |
---|
1120 | | #endif |
---|
1121 | | |
---|
1122 | | #if 1 |
---|
1123 | | uint32_t last_sph = ntohl(*(quadlet_t *)(data+8+(n_events-1)*event_length)); |
---|
1124 | | m_last_timestamp = sphRecvToFullTicks(last_sph, m_handler->getCycleTimer()); |
---|
1125 | | #endif |
---|
1126 | | //debugOutput(DEBUG_LEVEL_VERBOSE,"ave ticks=%g\n",(m_last_timestamp-m_last_timestamp2)/8.0); |
---|
| 1054 | // Acquire the timestamp of the last frame in the packet just |
---|
| 1055 | // received. Since every frame from the MOTU has its own timestamp |
---|
| 1056 | // we can just pick it straight from the packet. |
---|
| 1057 | uint32_t last_sph = ntohl(*(quadlet_t *)(data+8+(n_events-1)*event_length)); |
---|
| 1058 | m_last_timestamp = sphRecvToFullTicks(last_sph, m_handler->getCycleTimer()); |
---|
1142 | | // the next (possible) sample is not this one, but lies |
---|
1143 | | // SYT_INTERVAL * rate later |
---|
1144 | | float frames_per_packet=m_framerate<=48000?8:(m_framerate<=96000?16:32); |
---|
1145 | | uint64_t ts=addTicks(m_last_timestamp, |
---|
1146 | | (uint64_t)(frames_per_packet * m_ticks_per_frame)); |
---|
1147 | | // uint64_t ts=addTicks(m_last_timestamp, |
---|
1148 | | // (uint64_t)(m_ticks_per_frame)); |
---|
1149 | | |
---|
1150 | | // set the timestamp as if there will be a sample put into |
---|
1151 | | // the buffer by the next packet. This means we use the timestamp |
---|
1152 | | // corresponding to the last frame which would have been added to the |
---|
1153 | | // buffer this cycle if we weren't disabled. |
---|
1154 | | // |
---|
1155 | | // FIXME: in theory m_last_timestamp is already equal to the |
---|
1156 | | // timestamp of the last frame/sample in this packet since |
---|
1157 | | // that's what we used to set it in the first place. However, |
---|
1158 | | // if m_last_timestamp is used to set the buffer tail we get a |
---|
1159 | | // series of "difference too large" warnings during the early |
---|
1160 | | // stages after enabling. These tend to indicate that the |
---|
1161 | | // buffer timestamp is one packet out. Using ts (which predicts |
---|
1162 | | // the timestamp of the last frame of the *next* packet) seems |
---|
1163 | | // to stop these warnings most of the time and allow for a |
---|
1164 | | // smoother startup. |
---|
1165 | | // On second thoughts, perhaps it doesn't help much after all. |
---|
1166 | | // m_data_buffer->setBufferTailTimestamp(ts); |
---|
| 1074 | // Set the timestamp as if a sample was put into the buffer by |
---|
| 1075 | // this present packet. This means we use the timestamp |
---|
| 1076 | // corresponding to the last frame which would have been added |
---|
| 1077 | // to the buffer this cycle if we weren't disabled - that is, |
---|
| 1078 | // m_last_timestamp. |
---|