alsa-project / snd-firewire-ctl-services

A set of server programs for audio and music units on IEEE 1394 bus supported by Linux sound subsystem a.k.a. ALSA.
GNU General Public License v3.0
35 stars 5 forks source link

Unexpected response status code 21 running snd-bebob-ctl-service against PreSonus Firebox #174

Closed ascherkus closed 6 months ago

ascherkus commented 1 year ago

Hi there! Thanks for all the work supporting firewire devices.

I confirmed I can use the PreSonus Firebox hardware DSP mixer via libffado v2.4.7 but wanted to see if I could get it running with ALSA. I'm somewhat familiar with Linux audio internals but wanted to file an issue in case I'm missing something obvious in either building the project or invoking it.

I built the following:

Here's my output:

$ snd-bebob-ctl-service -l debug 0
2023-07-03T20:31:42.741987Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=MediaClockParameters { freq_idx: 1 } res=Ok(())
2023-07-03T20:31:42.748050Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=SamplingClockParameters { src_idx: 0 } res=Ok(())
2023-07-03T20:31:42.781479Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=AvcLevelParameters { levels: [0, 0, 0, 0, 0, 0] } res=Ok(())
2023-07-03T20:31:42.792918Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=AvcLevelParameters { levels: [0, 0] } res=Ok(())
2023-07-03T20:31:42.827229Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=AvcLevelParameters { levels: [0, 0, 0, 0, 0, 0] } res=Ok(())
2023-07-03T20:31:42.833004Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=AvcLevelParameters { levels: [0] } res=Ok(())
2023-07-03T20:31:42.844518Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=AvcLevelParameters { levels: [0, 0] } res=Ok(())
2023-07-03T20:31:42.878950Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=AvcLrBalanceParameters { balances: [32512, -32768, 32512, -32768, 32512, -32768] } res=Ok(())
2023-07-03T20:31:42.890431Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=AvcLrBalanceParameters { balances: [32512, -32768] } res=Ok(())
2023-07-03T20:31:42.924342Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=AvcMuteParameters { mutes: [false, false, false, false, false, false] } res=Ok(())
2023-07-03T20:31:42.935929Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=AvcMuteParameters { mutes: [false, false] } res=Ok(())
2023-07-03T20:31:42.970092Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=AvcMuteParameters { mutes: [false, false, false, false, false, false] } res=Ok(())
2023-07-03T20:31:42.975793Z DEBUG cache: snd_bebob_ctl_service::common_ctls: params=AvcMuteParameters { mutes: [false] } res=Err(Error { domain: g-file-error-quark, code: 21, message: "unexpected response status" })
Linux file operation error: , unexpected response status
takaswie commented 1 year ago

Hi,

Thanks for your report and I'm sorry for your inconvenience. Would I ask you to apply below patch and try building again?

diff --git a/Cargo.toml b/Cargo.toml
index e2ea7516a..0f06ffb92 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,7 +21,7 @@ members = [
 #    "protocols/fireworks",
 #    "protocols/motu",
 #    "protocols/oxfw",
-#    "protocols/bebob",
+    "protocols/bebob",
 #    "protocols/dice",
 #    "protocols/fireface",
 ]
@@ -34,7 +34,7 @@ members = [
 #ta1394-avc-audio = { path = "protocols/ta1394/audio" }
 #ta1394-avc-stream-format = { path = "protocols/ta1394/stream-format" }
 #ta1394-avc-ccm = { path = "protocols/ta1394/ccm" }
-#firewire-bebob-protocols = { path = "protocols/bebob" }
+firewire-bebob-protocols = { path = "protocols/bebob" }
 #firewire-digi00x-protocols = { path = "protocols/digi00x" }
 #firewire-dice-protocols = { path = "protocols/dice" }
 #firewire-fireworks-protocols = { path = "protocols/fireworks" }
diff --git a/runtime/bebob/src/presonus/firebox_model.rs b/runtime/bebob/src/presonus/firebox_model.rs
index f87dfb7ec..0f228953a 100644
--- a/runtime/bebob/src/presonus/firebox_model.rs
+++ b/runtime/bebob/src/presonus/firebox_model.rs
@@ -410,8 +410,8 @@ impl CtlModel<(SndUnit, FwNode)> for FireboxModel {
         self.headphone_ctl.cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
         self.mixer_phys_src_ctl
             .cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
-        self.mixer_stream_src_ctl
-            .cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
+        //self.mixer_stream_src_ctl
+        //    .cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
         self.mixer_out_ctl.cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
         self.phys_out_ctl
             .cache_selectors(&self.avc, FCP_TIMEOUT_MS)?;
ascherkus commented 1 year ago

Thanks for the quick response and no worries about the inconvenience!

It looks like both lines need to be commented out:

diff --git a/runtime/bebob/src/presonus/firebox_model.rs b/runtime/bebob/src/presonus/firebox_model.rs
index f87dfb7..fa4e1ad 100644
--- a/runtime/bebob/src/presonus/firebox_model.rs
+++ b/runtime/bebob/src/presonus/firebox_model.rs
@@ -410,9 +410,9 @@ impl CtlModel<(SndUnit, FwNode)> for FireboxModel {
         self.headphone_ctl.cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
         self.mixer_phys_src_ctl
             .cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
-        self.mixer_stream_src_ctl
-            .cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
-        self.mixer_out_ctl.cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
+        // self.mixer_stream_src_ctl
+        //     .cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
+        // self.mixer_out_ctl.cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
         self.phys_out_ctl
             .cache_selectors(&self.avc, FCP_TIMEOUT_MS)?;
         self.headphone_ctl

The program now doesn't crash and spits out a ton more logs: presonus-firebox.log

To be honest not sure what to do with snd-bebob-ctl-service now that I think it's running but that's more to do with my general unfamiliarity with alsa + firewire :grin:

ascherkus commented 1 year ago

Whoops my previous log file was truncated -- here's another copy: presonus-firebox2.log

takaswie commented 1 year ago
+        // self.mixer_stream_src_ctl
+        //     .cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;
+        // self.mixer_out_ctl.cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;

@ascherkus Thanks for your trial.

As you can see, Firebox does not allow software to control mute/unmute function for mixer stream source and mixer output. The diagram of internal signal flow is here:

Would I ask you to retrieve information from your device? If installing libhinawa with PyGObject and gobject-introspection, we can communicate to the device by Python 3 script. Below script is equivalent to the operation which is commented out in the above.

#!/usr/bin/env python3

import gi
gi.require_versions({'GLib': '2.0', 'Hinawa': '3.0'})
from gi.repository import GLib, Hinawa

from threading import Thread

def main() -> int:
    node = Hinawa.FwNode.new()
    node.open('/dev/fw1')

    ctx = GLib.MainContext.new()
    src = node.create_source()
    src.attach(ctx)

    dispatcher = GLib.MainLoop.new(ctx, False)
    th = Thread(target=lambda d: d.run(), args=(dispatcher,))
    th.start()

    fcp = Hinawa.FwFcp.new()
    fcp.bind(node)

    # Equivalent to 'self.mixer_stream_src_ctl.cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;'.
    cmd = [
        0x01,
        0x80,
        0xb8,
        0x81,   # Feature function block (= feature)
        0x08,   # Function block ID (= 0x08).
        0x10,   # Control attribute (= current)
        0x02,   # Selector length (= 2)
        0x00,   # Audio channel number (= master)
        0x01,   # Control selector (= mute)
        0x01,   # length of control data (= 1)
        0xff,   # on (= 0x70), off (= 0x60)
        0x00,   # Padding for quadlet alignment
    ]
    run_fcp_avc(fcp, cmd, 'FireboxMixerStreamSourceProtocol')

    # Equivalent to 'self.mixer_out_ctl.cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;'.
    cmd = [
        0x01,
        0x80,
        0xb8,
        0x81,   # Feature function block (= feature)
        0x09,   # Function block ID (= 0x09).
        0x10,   # Control attribute (= current)
        0x02,   # Selector length (= 2)
        0x01,   # Audio channel number (= ch0)
        0x01,   # Control selector (= mute)
        0x01,   # length of control data (= 1)
        0xff,   # on (= 0x70), off (= 0x60)
        0x00,   # Padding for quadlet alignment
    ]
    run_fcp_avc(fcp, cmd, 'FireboxMixerOutputProtocol')

    # Equivalent to 'self.mixer_out_ctl.cache_mutes(&self.avc, FCP_TIMEOUT_MS)?;'.
    cmd = [
        0x01,
        0x80,
        0xb8,
        0x81,   # Feature function block (= feature)
        0x09,   # Function block ID (= 0x09).
        0x10,   # Control attribute (= current)
        0x02,   # Selector length (= 2)
        0x02,   # Audio channel number (= ch1)
        0x01,   # Control selector (= mute)
        0x01,   # length of control data (= 1)
        0xff,   # on (= 0x70), off (= 0x60)
        0x00,   # Padding for quadlet alignment
    ]
    run_fcp_avc(fcp, cmd, 'FireboxMixerOutputProtocol')

    fcp.unbind()

    dispatcher.quit()
    th.join()

def run_fcp_avc(fcp: Hinawa.FwFcp, cmd: list[int], label: str):
    resp = fcp.avc_transaction(cmd, [0] * 512, 100)
    print(label)
    for i, b in enumerate(resp):
        print('[{:2}] 0x{:02x}'.format(i, b))

if __name__ == '__main__':
    exit(main())

When being successful, you can see the content of response like this:

$ ./sample
FireboxMixerStreamSourceProtocol
[ 0] 0x08
[ 1] 0x80
[ 2] 0xb8
[ 3] 0x81
[ 4] 0x08
[ 5] 0x10
[ 6] 0x02
[ 7] 0x00
[ 8] 0x01
[ 9] 0x01
[10] 0xff
[11] 0x00
FireboxMixerOutputProtocol
[ 0] 0x08
[ 1] 0x80
[ 2] 0xb8
[ 3] 0x81
[ 4] 0x09
[ 5] 0x10
[ 6] 0x02
[ 7] 0x01
[ 8] 0x01
[ 9] 0x01
[10] 0xff
[11] 0x00
FireboxMixerOutputProtocol
[ 0] 0x08
[ 1] 0x80
[ 2] 0xb8
[ 3] 0x81
[ 4] 0x09
[ 5] 0x10
[ 6] 0x02
[ 7] 0x02
[ 8] 0x01
[ 9] 0x01
[10] 0xff
[11] 0x00

If you are interested in the content, please refer to documentation published by 1394 trading association (but the organization is already dissolved...)

Mute function itself:

Function Control Protocol:

takaswie commented 8 months ago

Ping @ascherkus.

takaswie commented 6 months ago

Closed since no reactions from the reporter during the few months.