takaswie / linux-firewire-dkms

Currently this repository is maintained for Linux firewire subsystem and unit drivers.
http://ieee1394.docs.kernel.org/
39 stars 8 forks source link

Digidesign Digi 003R clicks & pops while recording #26

Closed VennStone closed 3 years ago

VennStone commented 4 years ago

Picked up a Digidesign Digi 003R to play around with and for the most part it worked. It can connect at 4800/4100 256 and all of the routing appears to work in Ardour 5.12.

Unfortunately it generates a little pop/click every 5 to 7 seconds in the recording and output. This was using kernel 4.19 and 5.4 with and without snd-firewire-improve from.

I was wondering if there was any helpful output / logs I could provide to help track this issue?

takaswie commented 4 years ago

Hi,

Thanks for the report.

Unfortunately it generates a little pop/click every 5 to 7 seconds in the recording and output. This was using kernel 4.19 and 5.4 with and without snd-firewire-improve from.

I was wondering if there was any helpful output / logs I could provide to help track this issue?

I've acknowledged this issue for a long ago. This is a kind of issue dependent of each kind of devices.

IEC 61883-1/6 packet streaming engine in ALSA firewire stack transfers a series of isochronous packets which includes PCM frames exactly as the same as configured sampling rate[1]; e.g. 44100. This implementation relies on a feature called as 'clock recovery' in device side, which is a part of IEC 61883-1/6.

On the other hand, actual devices in market doesn't have the feature (sign...). Some of them expects to receive the number of PCM frames adjusted its internal sampling clock; e.g. 44092. Furthermore, the number is variable at time; e.g. 44092-44104. The mismatch between the 'ideal' throughput of the engine and the actual frequency of internal clock is the reason of clicks and pops, in my understanding.

Therefore such kind of device expects the engine to perform 'clock recovery' by analyzing a series of isochronous packets from the device for the number of PCM frames on isochronous packet to the device. In this year, I'll tackle this issue, however I've had no idea to achieve the 'clock recovery' for the engine yet.

(I note that due to the above design it's not possible to synchronize sampling clocks per devices on the same IEEE 1394 bus. They work according to their own internal clocks, against some 'myths' of FireWire. They can't adjust internal sampling clock by a series of timestamp in received isochronous packets.)

[1] https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git/tree/sound/firewire/amdtp-stream.c#n741

VennStone commented 4 years ago

Thanks for taking a look at it. That seems like quite a daunting task but I wish you the best of luck. I will keep the 003 in the rack since it makes a good shelf.

I don't know if it's of any value but I did notice the 003 generates an inaudible xrun in Ardour every 2.5 minutes or so. https://i.imgur.com/outPJR7.jpg

Cheers, Venn

takaswie commented 4 years ago

Hi,

I don't know if it's of any value but I did notice the 003 generates an inaudible xrun in Ardour every 2.5 minutes or so.

Hm. I'd like to get some parameters relevant to intermeditate PCM ring buffer when the XRUN occurs. Would you tell me the size of period and buffer in the PCM ring buffer?

VennStone commented 4 years ago

Sample rate: 48000 Buffer Size: 256 Periods: 3

I think that is the information you requested? If not let me know and I will provide it.

takaswie commented 4 years ago

Sample rate: 48000 Buffer Size: 256 Periods: 3

I think that is the information you requested? If not let me know and I will provide it.

They're what I expected. Additionally, which version of Linux kernel did you use to see the periodical XRUNs; v4.19 or v5.4 or the both? Which backend did you use for Ardour; jackd or direct ALSA application?

VennStone commented 4 years ago

I observed periodical XRUNs in v4.19 and v5.4. Right now the box is running the stock RT kernel.

OS: Debian 10.3 Kernel: 4.19.0-8-rt-amd64 Ardour: Jackd backend.

takaswie commented 4 years ago

Hi,

Sample rate: 48000 Buffer Size: 256 Periods: 3 OS: Debian 10.3 Kernel: 4.19.0-8-rt-amd64 Ardour: Jackd backend.

Thanks for the report. I tested my digi003 rack and got different result in this environment:

Theoretically, if the XRUN occurs due to kernel driver problem, the periodical XRUN also occurs in the above environment. Actually not. I cannot see such periodical XRUNs. XRUN occurs but it's random period. Furthermore, I can't find any logs which means that ALSA driver encounter XRUN status.

zamaudio commented 4 years ago

This issue is an instance of #24 (or at least related).

dylofpoke commented 4 years ago

I have just got myself a Digi 002 rack and will be trying it in Ardour (5.12, I think) with Ubuntu Studio (1604, I think) when I get hold of a firewire card and cable, so I'm very interested in getting it working and up for testing and giving anyone any info that will help...

dylofpoke commented 4 years ago

Also, I love that this is still actively being developed, as it will hopefully save a lot of high quality, cheaply available audio interfaces from obsolescence, which is a very noble thing to be doing!

zamaudio commented 4 years ago

@dylofpoke I highly recommend getting a FW800 PCIe controller and using a FW800 -> FW400 cable to connect to a 002/003 it just seems to work better than a FW400 controller. I use one from TI with a XIO22I3BZAY chip. Something like this: https://eiratek.com/product/pci-e-to-1394-card-firewire-b-800/ Having said that, the driver still needs work to fix the xruns.

takaswie commented 4 years ago

Having said that, the driver still needs work to fix the xruns.

No. The issue mentioned by this bug brings no XRUNs. It's the most important point that the periodical pop/click comes from the device design that the total number of processed PCM frames per second is not exactly the same as sampling rate. On the other hand, ALSA firewire-digi00x driver transfers the same number of PCM frames as sampling rate (=sampling transfer frequency).

The click/pop noise doesn't related to XRUNs detected by any software.

zamaudio commented 4 years ago

@takaswie ok, so it's the device design fault. Regardless of the cause of the fault, we still want to have the device functioning without clicks and pops. That means a workaround is needed in the driver, that is what I meant. For example, on windows and mac the device works without any problem.

takaswie commented 4 years ago

For example, on windows and mac the device works without any problem.

This is natural. The drivers for Windows/MacOS has been developed by vendor itself, which is responsible for the design itself.

Regardless of the cause of the fault, we still want to have the device functioning without clicks and pops. That means a workaround is needed in the driver, that is what I meant.

Please work for it.

zamaudio commented 4 years ago

Please work for it.

Is there anything I can provide that would make it easier for you to do it? I don't have much time these days for writing kernel code. I have some idea of how to fix it though.

takaswie commented 4 years ago

Hi @dylofpoke ,

Although the device itself is obsolescence, the FLOSS driver (snd-firewire-digi00x) is under development. This is due to the reason that no one in FLOSS world is not the original designer of the device.

So, if you use the device, it's better to take enough care of kernel version.

v4.1
      5      32     271
v4.2
     25     258    2012
v4.3
      4      31     277
v4.4
     75     743    5997
v4.5
     31     304    2298
v4.6
     24     249    1826
v4.7
     28     303    2319
v4.8
      2      18     148
v4.9
      4      36     302
v4.10
      6      61     459
v4.11
     15     133    1149
v4.12
     56     536    4314
v4.13
      8      78     648
v4.14
     10      98     788
v4.15
      2      18     192
v4.16
      2      13     102
v4.17
      4      42     308
v4.18
     27     261    1913
v4.19
     17     179    1282
v5.0
     41     452    3429
v5.1
     22     240    1854
v5.2
     12     102     955
v5.3
    116    1229   10120
v5.4
     54     541    4297
v5.5
     54     624    4390

This statistics is for the number of patches applied to upstream kernel for ALSA firewire stack per version in the leftmost of each line. You can see the stack sometimes got the big changes. I'd like you to use the latest version of kernel as possible.

Ubuntu Studio 16.04 is LTS (=Long Term Support) and HWE (hardware enablement) is available. I don't know exactly the latest version of kernel in xenial/HWE (v4.15 or so, perhaps) but I recommend to use the latest version of LTS because the enhanced version of driver is available.

P.S. this output comes from the script below:

#!/bin/bash

for curr in $(seq 1 19); do
  prev=$(($curr - 1))
  echo v4.$curr
  git log --oneline v4.$prev..v4.$curr sound/firewire include/uapi/sound/firewire.h | wc
done

echo v5.0
git log --oneline v4.19..v5.0 sound/firewire include/uapi/sound/firewire.h | wc

for curr in $(seq 1 5); do
  prev=$(($curr - 1))
  echo v5.$curr
  git log --oneline v5.$prev..v5.$curr sound/firewire include/uapi/sound/firewire.h | wc
done
zamaudio commented 4 years ago

@takaswie As I mentioned in #24, as you know, when the SYT value is always zero for this device, you cannot do clock recovery from the packets alone, but you can measure a system timestamp instead when the packet arrives and use that for clock recovery with a delay locked loop. This is not my idea alone, but works for other Oxford devices that have SYT = 0 in ffado.

takaswie commented 4 years ago

@zamaudio Just an idea can make nothing.

zamaudio commented 4 years ago

@takaswie https://kokkinizita.linuxaudio.org/papers/usingdll.pdf I have used this algorithm before to implement clock recovery. It has C code example.

zamaudio commented 4 years ago

See https://github.com/janosvitok/ffado/blob/master/trunk/libffado/src/libstreaming/amdtp-oxford/AmdtpOxfordReceiveStreamProcessor.cpp#L40 for ffado implementation of pseudo-converting non-blocking to blocking transmission.

/* The issues with the FCA202 (and possibly other oxford FW92x devices) are:
 * - they transmit in non-blocking mode
 * - the timestamps are not correct
 *
 * This requires some workarounds.
 *
 * The approach is to 'convert' non-blocking into blocking so
 * that we can use the existing streaming system.
 *
 * The streamprocessor has a "pseudo-packet" buffer that will collect
 * all frames present. Once one SYT_INTERVAL of frames is present, we indicate
 * that a packet has been received.
 *
 * To overcome the timestamping issue we use the time-of-arrival as a timestamp.
 *
 */
takaswie commented 4 years ago

@zamaudio In IEEE 1394, isochronous packet transmission is governed by bus clock at 24.576MHz. Crystal oscillator is implemented on 1394 OHCI controller for the clock signal and it generates 49.152 MHz for divider. The controller also generates hardware IRQ depending on the clock. In this point, the device has enough accuracy for PCM frame processing.

However, in modern operating system, hardware IRQ is not handled immediately since the system implements some kind of lock primitive; e.g. spin-lock. Such lock primitive uses CPU feature of IRQ mask. The timing to execute software handler for the IRQ can be delayed and the sequence of IRQ handling includes jitter. At least, device driver developers understand it and take enough care of the jitter.

I don't know exactly what you call as system timestamp. As long as it's apart from the bus clock, it's not suitable for timestamp processing for isochronous packet on IEEE 1394. Reading current system time per call of IRQ handler doesn't make sense. In the IRQ handler, calculations should be done just by isochronous cycle which each packet has since the cycle comes from more reliable 24.576 MHz bus clock.

I'm on the above theory and have less interests in your idea.

takaswie commented 4 years ago

In IEEE 1394, isochronous packet transmission is governed by bus clock at 24.576MHz. Crystal oscillator is implemented on 1394 OHCI controller for the clock signal and it generates 49.152 MHz for divider. The controller also generates hardware IRQ depending on the clock. In this point, the device has enough accuracy for PCM frame processing.

However, in modern operating system, hardware IRQ is not handled immediately since the system implements some kind of lock primitive; e.g. spin-lock. Such lock primitive uses CPU feature of IRQ mask. The timing to execute software handler for the IRQ can be delayed and the sequence of IRQ handling includes jitter. At least, device driver developers understand it and take enough care of the jitter.

I don't know exactly what you call as system timestamp. As long as it's apart from the bus clock, it's not suitable for timestamp processing for isochronous packet on IEEE 1394. Reading current system time per call of IRQ handler doesn't make sense. In the IRQ handler, calculations should be fdone just by isochronous cycle which each packet has since the cycle comes from more reliable 24.576 MHz bus clock.

I'm on the above theory and have less interests in your idea.

@zamaudio For example, Linux kernel has a feature isolcpus cmdline option. When CPU IDs are indicated by the option, the CPUs are not used by task scheduler. This means that no user processes are scheduled to the CPU.

Linux kernel exposes smp_affinity node in sysfs to allow users to configure assignment of process to any CPU. This is also available for assignment of IRQ handler. When configure IRQ handler of Linux driver for 1394 OHCI controller (firewire-ohci kernel module) to the isolated CPU, we can control load of the CPU without any interrupt by processes and drivers for CPU locks, in short we can use some of CPUs just to handle IRQ from the 1394 OHCI controller.

When Configuring the above options, you can see the controller works with less jitter (<=1ms). For example, the firewire-ohci module has debug module option and value 4 take the module to dump timestamp when it runs IRQ handler (this is not equals to IRQ request itself). You can see the timestamp of dump in syslog and the jitter is quite low level. This is due to the 24.576 MHz clock apart from system.

Without the above configuration, the dump includes large jitters (>= several msec or several dozen msec or so). This is due to the CPU locks by process or the other drivers, I mentioned.

You can see that reading current system time at running IRQ handler is not good idea at all. It can include large jitters unsuitable for timestamp processing.

zamaudio commented 4 years ago

I don't know exactly what you call as system timestamp. As long as it's apart from the bus clock, it's not suitable for timestamp processing for isochronous packet on IEEE 1394.

As you know, the problem with the device is that the timestamps are missing from the packets, so you cannot do clock recovery from the packet information. We already agree on this. Therefore, any jittery timestamp for marking packet arrival is better than no timestamp. The idea is to use the (number of received frames in cycle / 8000) as a kind of timestamp and update a DLL on top of that to filter out the jitter periodically. With this in place, you can collect all the frames into a pseudo-packet until SYT_INTERVAL frames is filled, and then copy it to the real packet and mark the real packet as "arrived". Then you can use blocking transmission mode.

pneyrinck commented 3 years ago

The pro audio clocking features of the 003/002 allow the sample rate clock to be driven by external clock sources (SPDIF, Word Clock, or ADAT) and a user expects that that the PCM audio samples going between the DAW and the outside world are not modified whatsoever. Thus, the driver has to assume the device is not synchronized to the Firewire bus clock. If the driver sends the exact same number of blocks as received on average, then there will be no pops/clicks.

takaswie commented 3 years ago

Hi @pneyrinch,

If the driver sends the exact same number of blocks as received on average, then there will be no pops/clicks.

Yes. Although the way to calculate the 'average' is the item to be resolved, no one has proposal for it. They just took arguments and left.

pneyrinck commented 3 years ago

Hi @pneyrinch,

If the driver sends the exact same number of blocks as received on average, then there will be no pops/clicks.

Yes. Although the way to calculate the 'average' is the item to be resolved, no one has proposal for it. They just took arguments and left.

I sent you an email with some naive pseudo code. I hope it can help keep the discussion going. But please know that I do not yet understand how your driver's buffering operates to set up the talker packets.

Here is the naive pseudo-code:

void talkPackets[200]; void listenPackets[200]; void callbackForFirst100PacketsSent(); void callbackForSecond100PacketsSent(); void prepareTalkPacket(int packetIndex, int blockCount);

sampleRate = 48000; int predictedBlocksPerPacket = sampleRate / 8000; for (packet=0; packet<200; packet++) { prepareTalkPacket(packet, predictedBlocksPerPacket); }

startIsochTransfers();

void callbackForFirst100PacketsSent() { for (packet=0; packet<100; packet++) { int blocksReceived = getBlocksReceivedForPacket(packet); prepareTalkPacket(packet, blocksReceived); } }

void callbackForSecond100PacketsSent(); { for (packet=100; packet<200; packet++) { int blocksReceived = getBlocksReceivedForPacket(packet); prepareTalkPacket(packet, blocksReceived); } }

The idea is to initially use the predicted block count for talker packets. But then after listen packets are received, use the actual block counts that the device is providing.

takaswie commented 3 years ago

Hi @pneyrinck ,

Thanks for the pseudo code.

void* talkPackets[200];
void* listenPackets[200];
void callbackForFirst100PacketsSent();
void callbackForSecond100PacketsSent();
void prepareTalkPacket(int packetIndex, int blockCount);

sampleRate = 48000;

int predictedBlocksPerPacket = sampleRate / 8000;
for (packet=0; packet<200; packet++)
{
  prepareTalkPacket(packet, predictedBlocksPerPacket);
}

startIsochTransfers();

void callbackForFirst100PacketsSent()
{
  for (packet=0; packet<100; packet++)
  {
    int blocksReceived = getBlocksReceivedForPacket(packet);
    prepareTalkPacket(packet, blocksReceived);
  }
}

void callbackForSecond100PacketsSent();
{
  for (packet=100; packet<200; packet++)
  {
    int blocksReceived = getBlocksReceivedForPacket(packet);
    prepareTalkPacket(packet, blocksReceived);
  }
}

I guess you have experiences for IEEE 1722 due to usage of the words, talker and listener. In my understanding, IEC-61883-1/6 is an ancestor of the specification.

The idea is to initially use the predicted block count for talker packets. But then after listen packets are received, use the actual block counts that the device is providing.

It looks good. I guess that the number for packet (=100) is ad-hoc one, and we need to find the number better to each device types with many cases (IEC 61883-1/6 packet streaming engine in ALSA firewire stack is designed to support 8 different types of device. Digidesign 00x family is one of the types).

pneyrinck commented 3 years ago

I guess you have experiences for IEEE 1722 due to usage of the words, talker and listener. In my understanding, IEC-61883-1/6 is an ancestor of the specification.

I have been looking at the book "FireWire System Architecture" by Don Anderson and the Mac OS Firewire APIs which use 'talker' and 'listener.'

It looks good. I guess that the number for packet (=100) is ad-hoc one, and we need to find the number better to each device types with many cases (IEC 61883-1/6 packet streaming engine in ALSA firewire stack is designed to support 8 different types of device. Digidesign 00x family is one of the types).

Yes, the number 100 is an example I chose out of thin air.

takaswie commented 3 years ago

I have been looking at the book "FireWire System Architecture" by Don Anderson and the Mac OS Firewire APIs which use 'talker' and 'listener.'

Oh, surprising! I have a bias that the word, 'talker' and 'listener' first appeared in documentation about IEEE 1722 or Audio and Video Bridging (AVB) since I've never read any documentation about IEEE 1394 packet streaming with the words. I'm going to refer to it, thanks.

pneyrinck commented 3 years ago

I have some different pseudo-code to share. I am successfully using this system to keep the output synchronized to the input for the driver I am developing on Mac OS. The code calculates the average sample rate based on blocks received each isoch frame. The average sample rate allows it to calculate the number of blocks to send. It can also be used to synthesize a SYT value.

double mListenerAverageSampleRate; double mTalkerBlockCounter;

void init(double nominalSampleRate) { mListenerAverageSampleRate = nominalSampleRate; //48000, 44100, 96000, 88200, ... mTalkerBlockCounter = 0.0; }

void processSomeListenPacketsCallback() { for (int packet=0; packet<numPackets; packet++) { blocksReceived = getNumBlocksForPacket(packet); mListenerAverageSampleRate = (float)blocksReceived 8000.0 0.001 + mListenerAverageSampleRate * 0.999; //lowpass filter with adhoc time constant } }

void processTalkerPackets() { for (int packet=0; packet<numPackets; packet++) { mTalkerBlockCounter += (mListenerAverageSampleRate * .000125); int packetBlockCount = (int)mTalkerBlockCounter; mTalkerBlockCounter -= packetBlockCount; setNumBlocksForPacket(packetBlockCount); } }

takaswie commented 3 years ago

Hi @pneyrinck ,

Thanks you to share the pceudo-code.

double mListenerAverageSampleRate;
double mTalkerBlockCounter;

void init(double nominalSampleRate)
{
  mListenerAverageSampleRate = nominalSampleRate; //48000, 44100, 96000, 88200, ...
  mTalkerBlockCounter = 0.0;
}

void processSomeListenPacketsCallback()
{
  for (int packet=0; packet<numPackets; packet++)
  {
    blocksReceived = getNumBlocksForPacket(packet);
    mListenerAverageSampleRate = (float)blocksReceived * 8000.0 * 0.001 + mListenerAverageSampleRate * 0.999; //lowpass filter with adhoc time constant
  }
}

void processTalkerPackets()
{
  for (int packet=0; packet<numPackets; packet++)
  {
    mTalkerBlockCounter += (mListenerAverageSampleRate * .000125);
    int packetBlockCount = (int)mTalkerBlockCounter;
    mTalkerBlockCounter -= packetBlockCount;
    setNumBlocksForPacket(packetBlockCount);
  }
}

I write Python 3 script for the pseudo code: https://gist.github.com/takaswie/34bef9035fb15a7e3f26545ca9867965

You can print parameters for each packet, when executing the script to text logs which I shared before: https://lore.kernel.org/alsa-devel/20210327084024.GA16753@workstation/T/#t

$ head -n 100 digi003-console-44100.csv > part.csv
$ /tmp/digi00x-parser  part.csv 16
sec cycle | isoc-ch:0    to device          | talker to device                  | isoc-ch:1  from device                       |
          | size dbs db dbc syt    acum-db  | db dbc accum-db diff computed-stf | size dbs db dbc syt    accum-db computed-stf |
 ======== | =============================== | ================================= | ============================================ |
  30 6833 |  616  19  8  88 0x477b        8 |  5   5        5   -3 44100.000000 |  388  19  5  49 0x0000        5 44095.900000 |
  30 6834 |    8  19  0  96 0xffff        8 |  6  11       11   +3 44100.000000 |  464  19  6  54 0x0000       11 44099.804100 |
  30 6835 |  616  19  8  96 0x60e5       16 |  5  16       16   +0 44100.000000 |  388  19  5  60 0x0000       16 44095.704296 |
  30 6836 |  616  19  8 104 0x764f       24 |  6  22       22   -2 44100.000000 |  464  19  6  65 0x0000       22 44099.608592 |
  30 6837 |    8  19  0 112 0xffff       24 |  5  27       27   +3 44100.000000 |  388  19  5  71 0x0000       27 44095.508983 |
  30 6838 |  616  19  8 112 0x8bba       32 |  6  33       33   +1 44100.000000 |  464  19  6  76 0x0000       33 44099.413474 |
  30 6839 |  616  19  8 120 0xa524       40 |  5  38       38   -2 44100.000000 |  388  19  5  82 0x0000       38 44095.314061 |
  30 6840 |    8  19  0 128 0xffff       40 |  6  44       44   +4 44100.000000 |  464  19  6  87 0x0000       44 44099.218746 |
  30 6841 |  616  19  8 128 0xba8e       48 |  5  49       49   +1 44100.000000 |  388  19  5  93 0x0000       49 44095.119528 |
  30 6842 |  616  19  8 136 0xd3f8       56 |  6  55       55   -1 44100.000000 |  464  19  6  98 0x0000       55 44099.024408 |
  30 6843 |  616  19  8 144 0xe962       64 |  5  60       60   -4 44100.000000 |  464  19  6 104 0x0000       61 44102.925384 |
  30 6844 |    8  19  0 152 0xffff       64 |  6  66       66   +2 44100.000000 |  388  19  5 110 0x0000       66 44098.822458 |
  30 6845 |  616  19  8 152 0x02cd       72 |  5  71       71   -1 44100.000000 |  464  19  6 115 0x0000       72 44102.723636 |
  30 6846 |  616  19  8 160 0x1837       80 |  6  77       77   -3 44100.000000 |  388  19  5 121 0x0000       77 44098.620912 |
  30 6847 |    8  19  0 168 0xffff       80 |  5  82       82   +2 44100.000000 |  464  19  6 126 0x0000       83 44102.522291 |
  30 6848 |  616  19  8 168 0x31a1       88 |  6  88       88   +0 44100.000000 |  388  19  5 132 0x0000       88 44098.419769 |
  30 6849 |  616  19  8 176 0x470b       96 |  5  93       93   -3 44098.419769 |  464  19  6 137 0x0000       94 44102.321349 |
  30 6850 |    8  19  0 184 0xffff       96 |  6  99       99   +3 44098.419769 |  388  19  5 143 0x0000       99 44098.219028 |
  30 6851 |  616  19  8 184 0x6076      104 |  5 104      104   +0 44098.419769 |  464  19  6 148 0x0000      105 44102.120809 |
  30 6852 |  616  19  8 192 0x75e0      112 |  6 110      110   -2 44098.419769 |  388  19  5 154 0x0000      110 44098.018688 |
  30 6853 |    8  19  0 200 0xffff      112 |  5 115      115   +3 44098.419769 |  464  19  6 159 0x0000      116 44101.920669 |
  30 6854 |  616  19  8 200 0x8b4a      120 |  6 121      121   +1 44098.419769 |  388  19  5 165 0x0000      121 44097.818749 |
  30 6855 |  616  19  8 208 0xa4b4      128 |  5 126      126   -2 44098.419769 |  464  19  6 170 0x0000      127 44101.720930 |
  30 6856 |    8  19  0 216 0xffff      128 |  6 132      132   +4 44098.419769 |  388  19  5 176 0x0000      132 44097.619209 |
  30 6857 |  616  19  8 216 0xba1f      136 |  5 137      137   +1 44098.419769 |  464  19  6 181 0x0000      138 44101.521590 |
  30 6858 |  616  19  8 224 0xd389      144 |  6 143      143   -1 44098.419769 |  388  19  5 187 0x0000      143 44097.420068 |
  30 6859 |  616  19  8 232 0xe8f3      152 |  5 148      148   -4 44098.419769 |  464  19  6 192 0x0000      149 44101.322648 |
  30 6860 |    8  19  0 240 0xffff      152 |  6 154      154   +2 44098.419769 |  388  19  5 198 0x0000      154 44097.221326 |
  30 6861 |  616  19  8 240 0x025d      160 |  5 159      159   -1 44098.419769 |  464  19  6 203 0x0000      160 44101.124104 |
  30 6862 |  616  19  8 248 0x17c7      168 |  6 165      165   -3 44098.419769 |  388  19  5 209 0x0000      165 44097.022980 |
  30 6863 |    8  19  0   0 0xffff      168 |  5 170      170   +2 44098.419769 |  464  19  6 214 0x0000      171 44100.925957 |
  30 6864 |  616  19  8   0 0x3132      176 |  6 176      176   +0 44098.419769 |  388  19  5 220 0x0000      176 44096.825031 |

I have some different pseudo-code to share. I am successfully using this system to keep the output synchronized to the input for the driver I am developing on Mac OS. The code calculates the average sample rate based on blocks received each isoch frame. The average sample rate allows it to calculate the number of blocks to send. It can also be used to synthesize a SYT value.

The computation of value for SYT field is bit complicated for non-blocking transmission method, since the position of data block for SYT inner packet differs depending on data block counter. Please refer to clause 7.2 Transmission of timinginformation in 'Audio and Music Data Transmission Protocol 2.3' (1394 Trade Association, April 24, 2012, Document 2009013).

http://1394ta.org/developers/publicspecs/2009013.pdf

I recommend you to use blocking method if computing SYT value correctly. But in my opinion, any device in Digi 00x series doesn't use the value of SYT for timing synchronization so we can be lazy to compute it.

takaswie commented 3 years ago

Hi,

I attempt to implement media clock recovery to suppress the issue. If still interested, please test current HEAD of topic/media-clock-recovery remote branch (3a2c5fd52657).

VennStone commented 3 years ago

Hooked up the 003R this morning and tested it out. Recorded for 10 minutes and didn't generate any xruns. No click or pops in the recording.

Debian Buster running 5.11.2-rt.

jackd -R -S -d alsa -d hw:D003Rack -r 48000 -p 128 -n 3

Screenshot_2021-05-27_13-34-07

takaswie commented 3 years ago

Hooked up the 003R this morning and tested it out. Recorded for 10 minutes and didn't generate any xruns. No click or pops in the recording.

Good to hear it.

I'm going to post patchset to upstream next week, then close the issue.

Thanks.

zamaudio commented 3 years ago

@LGCW Can you please try fpp 16 and 2 buffers? A friend of mine said he used to run jack/ffado at this level without problems.

does it work better than jack with ffado? 128 is better than I was ever able to get for my device (different driver though) but with ffado/jack 16/2 worked fine.

takaswie commented 3 years ago

At present, the drivers don't work well at 2 periods per buffer. Please use 3 periods per buffer.

On the other hand, you can use less number of frames per period; e.g. 32 frames/period, since the drivers queue isochronous packet in process context without waiting for hardware IRQ. Rather than expansion of the number of frames per period, it's preferable to reduce the number since userspace application can often takes drivers to queue isochronous packet according to the most recent bus cycle of IEEE 1394.

takaswie commented 3 years ago

I note that patchset is posted to upstream:

takaswie commented 3 years ago

The patchset is merged to upstream. The patches are also available in master branch of the repository. Let me close the issue. Thanks for your cooperation.

takaswie commented 3 years ago

P.S. The service program to control the device is available. Please refer to below URL if you are interested: