Implement a shairport-sync Airplay server into Node-Red

Hi there,

I would like to integrate a shairport-sync instance into my node-red flow.

The goal is being able to start / stop an airplay server listening to streams coming for iDevices and send that stream to the speaker output of a raspberry.

I (very naively) tried to import the shairport-sync module into a function node and piping the output stream to msg.speech and output it to a node-red-contrib-speakerpi-output node.

[
    {
        "id": "10ba55bf0ff143a6",
        "type": "function",
        "z": "c472a0f874cdcb87",
        "name": "",
        "func": "const airplay = new shairportSync();\nairplay.name = 'My Airplay Receiver';\nairplay.start();\nairplay.output.stream.pipe(msg.speech);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [
            {
                "var": "shairportSync",
                "module": "shairport-sync"
            }
        ],
        "x": 400,
        "y": 140,
        "wires": [
            [
                "3186abae45bab32d",
                "cc194a98caec879a"
            ]
        ]
    },
    {
        "id": "cc194a98caec879a",
        "type": "speakerpi-output",
        "z": "c472a0f874cdcb87",
        "choose": "streambased",
        "filename": "",
        "channels": "2",
        "bitdepth": "16",
        "samplerate": "44100",
        "name": "",
        "x": 640,
        "y": 140,
        "wires": [
            []
        ]
    }
]

As naive as it is, it doesn't work :blush: The function node claims that "TypeError: shairportSync is not a constructor".

Yet the module is installed as expected by node-red :

[info] Installing module: shairport-sync, version: latest
[info] Installed module: shairport-sync

Any idea ?

Thanks

It is likely the constructor is inside the import e.g....

const airplay = new shairportSync.shairportSync();

... But I don't know it's name.

Try adding it to the msg so you can inspect it in the debug sidebar...

msg.payload = shairportSync;
return msg;

Good idea, thanks.

I tried const airplay = new shairportSync.ShairportSync(); but it crashed node-red :

[red] Uncaught Exception:
[error] Error: spawn shairport-sync ENOENT

I'm not fluent in js and therefore might not understand exactly what I'm doing :blush:

Inspecting reports this :

object :
ShairportSync: function
Output: function
Stream: function
Pipe: function
Stdout: function

The source code for the module is here : GitHub - JJK801/node-shairport-sync: Node.js wrapper for shairport-sync, maybe it will give you some idea ?

A bit more details :

So I do this in setup :

import shairport-sync as shairportsync

(first field : shairport-sync, second field : shairportsync)

then

const airplay = new shairportsync.ShairportSync();
airplay.name = 'My Airplay Receiver';
airplay.start();
airplay.output.stream.pipe(msg.speech);
return msg;

Nodered crashes and reports this in the logs :

 node-red[3053]: 15 Apr 16:47:21 - [error] Error: spawn shairport-sync ENOENT
 node-red[3053]:     at Process.ChildProcess._handle.onexit (node:internal/child_process:283:19)
 node-red[3053]:     at onErrorNT (node:internal/child_process:476:16)
 node-red[3053]:     at processTicksAndRejections (node:internal/process/task_queues:83:21)

The module's documentation suggest to import like this :

import {ShairportSync} from 'shairport-sync';

Tried to add the braces in the setup tab but that didn't work.