[PATCH 0/6] ALSA: firewire: media clock recovery for syt-unaware devices
Hi,
In a commit f9e5ecdfc2c2 ("ALSA: firewire-lib: add replay target to cache sequence of packet"), I categorize devices supported by drivers in ALSA firewire stack in terms of the way to deliver effective sampling transfer frequency. This patchset is for the devices in group 1.
The devices in the group ignore presentation time to decide playback timing, therefore drivers to handle them can ignore processing presentation time expressed in syt field of CIP header. The sequence of the number of data blocks per packet is important for media clock recovery. With the patchset, the drivers are going to replay the sequence. For the detail of sequence replay, please refer to a commit 39c2649c71d8 ("ALSA: firewire-lib: replay sequence of incoming packets for outgoing packets").
Takashi Sakamoto (6): ALSA: fireworks: delete SYTMATCH clock source ALSA: fireworks: perform sequence replay for media clock recovery ALSA: oxfw: perform sequence replay for media clock recovery ALSA: firewire-digi00x: perform sequence replay for media clock recovery ALSA: firewire-tascam: perform sequence replay for media clock recovery ALSA: fireface: perform sequence replay for media clock recovery
sound/firewire/digi00x/amdtp-dot.c | 9 +++------ sound/firewire/digi00x/digi00x-stream.c | 8 ++++++-- sound/firewire/fireface/amdtp-ff.c | 2 +- sound/firewire/fireface/ff-stream.c | 6 +++++- sound/firewire/fireworks/fireworks.h | 2 +- sound/firewire/fireworks/fireworks_stream.c | 18 ++++++++++++++--- sound/firewire/oxfw/oxfw-stream.c | 22 +++++++++++++++++---- sound/firewire/tascam/tascam-stream.c | 21 ++++++++++++++++++-- sound/firewire/tascam/tascam.h | 1 + 9 files changed, 69 insertions(+), 20 deletions(-)
In the design of Fireworks board module, the device does't adjust its media clock voluntarily by the sequence of presentation time expressed in syt field of CIP header of received packet.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 654e28a6669f..49e12cf7c0e3 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -181,7 +181,7 @@ struct snd_efw_phys_meters { } __packed; enum snd_efw_clock_source { SND_EFW_CLOCK_SOURCE_INTERNAL = 0, - SND_EFW_CLOCK_SOURCE_SYTMATCH = 1, + // Unused. SND_EFW_CLOCK_SOURCE_WORDCLOCK = 2, SND_EFW_CLOCK_SOURCE_SPDIF = 3, SND_EFW_CLOCK_SOURCE_ADAT_1 = 4,
Echo Digital Audio Corporation had US patent US7599388B2 titled as 'System and method for high-bandwidth serial bus data transfer'. In the patent, dual-banked shared memory is used to deliver data between serial bus transmission and processor in FIFO way. The patent seems to be used for Fireworks board module. The mechanism is not compliant to synchronization based on presentation time expressed in syt field of CIP header. Fireworks board module takes care of the sequence of the number of data blocks per packet and just ignores the value of syt field.
This commit takes fireworks driver to performs sequence replay for media clock recovery. As long as I tested, Audiofire 2 and 4 have a quirk to skip an isochronous cycle several thousands after starting packet transmission.
The sequence replay is tested with below models: * Loud Technology Mackie 400f * Echo Audio Audiofire 12 (DSP model) * Echo Audio Audiofire 12 (FPGA model) * Echo Audio Audiofire 8 (DSP model) * Echo Audio Audiofire 8 (FPGA model) * Echo Audio Audiofire Pre8 * Echo Audio Audiofire 4 * Echo Audio Audiofire 2
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks_stream.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 6fc117c3a068..ac66f08acd6b 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -6,7 +6,7 @@ */ #include "./fireworks.h"
-#define READY_TIMEOUT_MS 100 +#define READY_TIMEOUT_MS 1000
static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream) { @@ -29,7 +29,7 @@ static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream) if (err < 0) return err;
- err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING); + err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING | CIP_UNAWARE_SYT); if (err < 0) { amdtp_stream_destroy(stream); cmp_connection_destroy(conn); @@ -264,6 +264,15 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw) return err;
if (!amdtp_stream_running(&efw->rx_stream)) { + unsigned int tx_init_skip_cycles; + + // Audiofire 2/4 skip an isochronous cycle several thousands after starting + // packet transmission. + if (efw->is_fireworks3 && !efw->is_af9) + tx_init_skip_cycles = 6000; + else + tx_init_skip_cycles = 0; + err = start_stream(efw, &efw->rx_stream, rate); if (err < 0) goto error; @@ -272,7 +281,10 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw) if (err < 0) goto error;
- err = amdtp_domain_start(&efw->domain, 0, false, false); + // NOTE: The device ignores presentation time expressed by the value of syt field + // of CIP header in received packets. The sequence of the number of data blocks per + // packet is important for media clock recovery. + err = amdtp_domain_start(&efw->domain, tx_init_skip_cycles, true, false); if (err < 0) goto error;
This commit takes ALSA oxfw driver to perform sequence replay for media clock recovery. Unfortunately, OXFW970 ASIC and its firmware has a quirk called jumbo payload which skips several isochronous cycles for packet transmission, thus the sequence replay is just adopted to OXFW971 ASIC. As well as Fireworks, OXFW ASICs also ignores presentation time against the way in IEC 61883-1/6.
The sequence replay is tested with below models: * Tascam FireOne * Stanton Magnetics SCS.1m * Apogee Duet FireWire
For below models, the sequence replay is tested to be disabled:
* Griffin FireWave * Behringer F-Control Audio 202 * Loud Technology Tapco Link.FireWire 4x6 * Loud Technology Mackie Onyx Satellite
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-stream.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 9792d4b4373c..0ef242fdd3bc 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -153,13 +153,13 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) struct cmp_connection *conn; enum cmp_direction c_dir; enum amdtp_stream_direction s_dir; - unsigned int flags; + unsigned int flags = CIP_UNAWARE_SYT; int err;
if (!(oxfw->quirks & SND_OXFW_QUIRK_BLOCKING_TRANSMISSION)) - flags = CIP_NONBLOCKING; + flags |= CIP_NONBLOCKING; else - flags = CIP_BLOCKING; + flags |= CIP_BLOCKING;
if (stream == &oxfw->tx_stream) { conn = &oxfw->out_conn; @@ -337,6 +337,9 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw) }
if (!amdtp_stream_running(&oxfw->rx_stream)) { + unsigned int tx_init_skip_cycles = 0; + bool replay_seq = false; + err = start_stream(oxfw, &oxfw->rx_stream); if (err < 0) { dev_err(&oxfw->unit->device, @@ -352,9 +355,20 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw) "fail to prepare tx stream: %d\n", err); goto error; } + + if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD) { + // Just after changing sampling transfer frequency, many cycles are + // skipped for packet transmission. + tx_init_skip_cycles = 400; + } else { + replay_seq = true; + } }
- err = amdtp_domain_start(&oxfw->domain, 0, false, false); + // NOTE: The device ignores presentation time expressed by the value of syt field + // of CIP header in received packets. The sequence of the number of data blocks per + // packet is important for media clock recovery. + err = amdtp_domain_start(&oxfw->domain, tx_init_skip_cycles, replay_seq, false); if (err < 0) goto error;
This commit takes ALSA firewire-digi00x driver to perform sequence replay for media clock recovery.
All of models in Digidesign digi00x family don't transfer isochronous packets till receiving isochronous packets. The on-the-fly mode is used for the purpose. They don't interpret presentation time expressed in syt field of received CIP, therefore the sequence of the number of data blocks per packet is important for media clock recovery.
The sequence replay is tested with below models:
* Digidesign Digi 002 * Digidesign Digi 002 Rack * Digidesign Digi 003 * Digidesign Digi 003 Rack
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/digi00x/amdtp-dot.c | 9 +++------ sound/firewire/digi00x/digi00x-stream.c | 8 ++++++-- 2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c index 398c57a6fb43..59b86c8d89e1 100644 --- a/sound/firewire/digi00x/amdtp-dot.c +++ b/sound/firewire/digi00x/amdtp-dot.c @@ -396,16 +396,13 @@ int amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir) { amdtp_stream_process_ctx_payloads_t process_ctx_payloads; - unsigned int flags; + unsigned int flags = CIP_NONBLOCKING | CIP_UNAWARE_SYT;
// Use different mode between incoming/outgoing. - if (dir == AMDTP_IN_STREAM) { - flags = CIP_NONBLOCKING; + if (dir == AMDTP_IN_STREAM) process_ctx_payloads = process_ir_ctx_payloads; - } else { - flags = CIP_BLOCKING; + else process_ctx_payloads = process_it_ctx_payloads; - }
return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM, process_ctx_payloads, sizeof(struct amdtp_dot)); diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index 2019f6533477..a15f55b0dce3 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -7,7 +7,7 @@
#include "digi00x.h"
-#define READY_TIMEOUT_MS 500 +#define READY_TIMEOUT_MS 200
const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = { [SND_DG00X_RATE_44100] = 44100, @@ -375,7 +375,11 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x) if (err < 0) goto error;
- err = amdtp_domain_start(&dg00x->domain, 0, false, false); + // NOTE: The device doesn't start packet transmission till receiving any packet. + // It ignores presentation time expressed by the value of syt field of CIP header + // in received packets. The sequence of the number of data blocks per packet is + // important for media clock recovery. + err = amdtp_domain_start(&dg00x->domain, 0, true, true); if (err < 0) goto error;
This commit takes ALSA firewire-tascam driver to perform sequence replay for media clock recovery.
The protocol specific to Tascam FireWire series is not compliant to IEC 61883-1/6 in terms of syt field of CIP. The protocol doesn't use presentation time in received CIP for playback timing. The sequence of the number of data blocks per packet is important for media clock recovery.
Although the devices in Tascam FireWire series transfer packets regardless of receiving packets, the tx packets includes no events in the beginning of streaming. It takes so long to multiplex any event into the packet after receiving the sequence of packets. As long as I experienced, it takes several thousands of isochronous cycle. Furthermore, just after changing sampling transmission frequency, it stops multiplexing event at once, then starts multiplexing again.
The sequence replay is tested with below models: * FW-1884 * FW-1804 * FW-1082
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/tascam/tascam-stream.c | 21 +++++++++++++++++++-- sound/firewire/tascam/tascam.h | 1 + 2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index 4811b60e5823..53e094cc411f 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -11,7 +11,7 @@ #define CLOCK_STATUS_MASK 0xffff0000 #define CLOCK_CONFIG_MASK 0x0000ffff
-#define READY_TIMEOUT_MS 500 +#define READY_TIMEOUT_MS 4000
static int get_clock(struct snd_tscm *tscm, u32 *data) { @@ -423,6 +423,8 @@ int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate, fw_iso_resources_free(&tscm->rx_resources); return err; } + + tscm->need_long_tx_init_skip = (rate != curr_rate); }
return 0; @@ -454,6 +456,7 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
if (!amdtp_stream_running(&tscm->rx_stream)) { int spd = fw_parent_device(tscm->unit)->max_speed; + unsigned int tx_init_skip_cycles;
err = set_stream_formats(tscm, rate); if (err < 0) @@ -473,7 +476,19 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) if (err < 0) goto error;
- err = amdtp_domain_start(&tscm->domain, 0, false, false); + if (tscm->need_long_tx_init_skip) + tx_init_skip_cycles = 16000; + else + tx_init_skip_cycles = 0; + + // MEMO: Just after starting packet streaming, it transfers packets without any + // event. Enough after receiving the sequence of packets, it multiplexes events into + // the packet. However, just after changing sampling transfer frequency, it stops + // multiplexing during packet transmission. Enough after, it restarts multiplexing + // again. The device ignores presentation time expressed by the value of syt field + // of CIP header in received packets. The sequence of the number of data blocks per + // packet is important for media clock recovery. + err = amdtp_domain_start(&tscm->domain, tx_init_skip_cycles, true, true); if (err < 0) return err;
@@ -499,6 +514,8 @@ void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm)
fw_iso_resources_free(&tscm->tx_resources); fw_iso_resources_free(&tscm->rx_resources); + + tscm->need_long_tx_init_skip = false; } }
diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h index 78b7a08986a1..28dad4eae9c9 100644 --- a/sound/firewire/tascam/tascam.h +++ b/sound/firewire/tascam/tascam.h @@ -99,6 +99,7 @@ struct snd_tscm { unsigned int push_pos;
struct amdtp_domain domain; + bool need_long_tx_init_skip; };
#define TSCM_ADDR_BASE 0xffff00000000ull
This commit takes ALSA fireface driver to perform sequence replay for media clock recovery.
The protocol specific to RME Fireface series is not compliant to IEC 61883-1/6 since it has no CIP header, therefore presentation time is not used for media clock recovery. The sequence of the number of data blocks per packet is important.
I note that the device skips an isochronous cycle corresponding to an empty packet or a NODATA packet in blocking transmission method of IEC 61883-1/6. For sequence replay, the cycle is handled as receiving an empty packet. Furthermore, it doesn't start packet transmission till receiving any packet.
The sequence replay is tested with below models:
* Fireface 400 * Fireface 800 * Fireface 802
I note that it is better to initialize Fireface 400 in advance by initialization transaction implemented in snd-fireface-ctl-service of snd-firewire-ctl-services project. You can see whether initialized or not by HOST LED on the device. Unless, the device often stops packet transmission even if session starts.
I guess the sequence replay also works well with below models:
* Fireface UFX * Fireface UCX
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireface/amdtp-ff.c | 2 +- sound/firewire/fireface/ff-stream.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/sound/firewire/fireface/amdtp-ff.c b/sound/firewire/fireface/amdtp-ff.c index 119c0076b17a..98177b0666d3 100644 --- a/sound/firewire/fireface/amdtp-ff.c +++ b/sound/firewire/fireface/amdtp-ff.c @@ -168,6 +168,6 @@ int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit, else process_ctx_payloads = process_it_ctx_payloads;
- return amdtp_stream_init(s, unit, dir, CIP_NO_HEADER, 0, + return amdtp_stream_init(s, unit, dir, CIP_BLOCKING | CIP_UNAWARE_SYT | CIP_NO_HEADER, 0, process_ctx_payloads, sizeof(struct amdtp_ff)); } diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index 97c356f2ac04..95bf405adb3d 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -199,7 +199,11 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) if (err < 0) goto error;
- err = amdtp_domain_start(&ff->domain, 0, false, false); + // NOTE: The device doesn't transfer packets unless receiving any packet. The + // sequence of tx packets includes cycle skip corresponding to empty packet or + // NODATA packet in IEC 61883-1/6. The sequence of the number of data blocks per + // packet is important for media clock recovery. + err = amdtp_domain_start(&ff->domain, 0, true, true); if (err < 0) goto error;
On Mon, 31 May 2021 04:50:57 +0200, Takashi Sakamoto wrote:
Hi,
In a commit f9e5ecdfc2c2 ("ALSA: firewire-lib: add replay target to cache sequence of packet"), I categorize devices supported by drivers in ALSA firewire stack in terms of the way to deliver effective sampling transfer frequency. This patchset is for the devices in group 1.
The devices in the group ignore presentation time to decide playback timing, therefore drivers to handle them can ignore processing presentation time expressed in syt field of CIP header. The sequence of the number of data blocks per packet is important for media clock recovery. With the patchset, the drivers are going to replay the sequence. For the detail of sequence replay, please refer to a commit 39c2649c71d8 ("ALSA: firewire-lib: replay sequence of incoming packets for outgoing packets").
Takashi Sakamoto (6): ALSA: fireworks: delete SYTMATCH clock source ALSA: fireworks: perform sequence replay for media clock recovery ALSA: oxfw: perform sequence replay for media clock recovery ALSA: firewire-digi00x: perform sequence replay for media clock recovery ALSA: firewire-tascam: perform sequence replay for media clock recovery ALSA: fireface: perform sequence replay for media clock recovery
Applied all six patches now. Thanks.
Takashi
participants (2)
-
Takashi Iwai
-
Takashi Sakamoto