Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

browser compatibility #1

Open
lmick002 opened this issue Nov 9, 2021 · 34 comments
Open

browser compatibility #1

lmick002 opened this issue Nov 9, 2021 · 34 comments

Comments

@lmick002
Copy link

lmick002 commented Nov 9, 2021

Is it possible to use this package in a browser environment?

@VictorQueiroz
Copy link
Collaborator

@lmick002 I don't think so. Maybe if you compile libshout itself using EMScripten, but I doubt it'd work out-of-the-box.

@starapple2
Copy link

I'm not clear about usage. If it's not in a browser how do you use this package?

@VictorQueiroz
Copy link
Collaborator

@starapple2 You should use it in a Node.js environment. It's a shortcut to the original xiph/Icecast-libshout that's written in C.

libshout

Libshout is a library for communicating with and sending data to an
icecast server. It handles the socket connection, the timing of the
data, and prevents bad data from getting to the icecast server.

With just a few lines of code, a programmer can easily turn any application
into a streaming source for an icecast server. Libshout also allows
developers who want a specific feature set (database access, request taking)
to concentrate on that feature set, instead of worrying about how server
communication works.

Please refer to the api reference and example code to start learning how to
use libshout in your own code.

Libshout is licensed under the LGPL. Please see the COPYING file for details.

If you have any questions or comments, please visit us at
http://www.icecast.org or email us at [email protected].

@starapple2
Copy link

@VictorQueiroz, thanks for your response. So I can include it in a project and connect to it from the browser via websockets, is that it? I am trying to get clarification on what I think @lmick002 was asking.

@VictorQueiroz
Copy link
Collaborator

VictorQueiroz commented Jul 3, 2023

@starapple2 I think the server uses TCP sockets. If I am correct, the best final solution would be to have a web socket server, that will be a proxy between the front-end and the TCP server, as it will do the translation for you.

For example:

website <> web socket server <> tcp server

@starapple2
Copy link

@VictorQueiroz, aha. Beyond the simplicity I envisaged. As is, what would be a use case? A Node.js dedktop app?

@VictorQueiroz
Copy link
Collaborator

@starapple2 In my case, I used it for creating a Node.js coimmand-line tool that would transmit the microphone audio to an Icecast server, so I could listen it from distance.

@starapple2
Copy link

@VictorQueiroz, in my case I want to send the mic from the browser window to Icecast.

@VictorQueiroz
Copy link
Collaborator

VictorQueiroz commented Jul 3, 2023

@starapple2 Then create the web socket server using a Node.js server and use the library to transmit whatever is sent to the websocket from the browser.

You can also use a WebWorker to avoid blocking the UI thread.

@starapple2
Copy link

@VictorQueiroz, I have created a server and have been looking for the correct libshout package to integrate and receive the connection from the client JavaScript. Each library I've seen appears to want a file rather than a blob that the script generates.

@VictorQueiroz
Copy link
Collaborator

VictorQueiroz commented Jul 3, 2023

@starapple2 Steps I suggest are:

  1. Create a web socket server using a Node.js server (install libshout)
  2. Send the encoded data (anything your Icecast server supports) of the microphone to the server (I suggest the OPUS codec. You can use this to encode the data to the OPUS format)
  3. In the web socket server, whatever comes in as an ArrayBuffer, sends to the icecast server using libshout

It's either this, or add WebSocket support for the icecast server, which is not the best choice IMHO.

@starapple2
Copy link

@VictorQueiroz I've just added libshout to the project and will see what's what. I am looking at the Readme and seeing a const to a directory path to a file so I imagine that would need to be amended for what is sent from the encoder.

@VictorQueiroz
Copy link
Collaborator

@starapple2 I think you can send the file by chunks however you want and the Icecast server clients will be able to play it as soon as there's something that can be decoded.

This library behaves exactly as the original libshout library. It even has the same methods, so you can just read the libshout documentation for more information about usage of the library.

If any method is missing, let me know, and I can add it quickly. I plan to add asynchronous functionalities to it later.

@starapple2
Copy link

@VictorQueiroz , I added opus-codec to the project. Is it then redundant based on what you said just now?

This is what I had originally written for some library shout:

const shout = require('shout');

const stream = shout.createStream({
  host: 'my-server.com',
  port: 8000,
  user: 'username',
  password: 'password',
  mount: '/stream',
  name: 'My Stream',
  genre: 'Talk, Reggae',
});

This part I need to be clear about:

// Read audio data from source and write it to the stream
 const audioData = readAudioDataFromFile();
 stream.write(audioData);

// Close the stream
 stream.end();

@VictorQueiroz
Copy link
Collaborator

@starapple2 Seems about right, but read this from my opus library to be able to use it properly. For now, you can try on the UI thread first for simplicity, but the audio decoding is supposed to be done in a WebWorker to avoid blocking the UI thread. Otherwise, you might have cropped milliseconds.

@VictorQueiroz
Copy link
Collaborator

@starapple2 There's this app I developed using this opus codec library, you can take a look at it:

https://github.com/rectimeproject/web

It might help you on audio decoding.

@starapple2
Copy link

@VictorQueiroz I have been using vanilla JavaScript to save a recording from an online example. I'm not familiar with React and most of these libraries as most of my Web activity is a bit of PHP and occasionally some simple JavaScript.

@starapple2
Copy link

@VictorQueiroz, I can't seem to initialize libshout using "require" and "import" isn't usable in this context. I keep getting Shout is not defined.

@VictorQueiroz
Copy link
Collaborator

VictorQueiroz commented Jul 3, 2023

@starapple2 In the code you sent, you're using shout package, not libshout. Can you try with libshout and see?

@starapple2
Copy link

starapple2 commented Jul 3, 2023 via email

@VictorQueiroz
Copy link
Collaborator

@starapple2 Can you provide more information, like, what Node.js version you're using?

@starapple2
Copy link

@VictorQueiroz it could just be that I'm doing something wrong:

const express = require('express')
const stream = require('libshout')
const shout = new Shout();
const fs = require('fs')
const { WebSocketServer } = require('ws')
const port = 3000

const app = express()

app.use(express.static('public'))

stream.shout({
  setHost: 'localhost',
  setProtocol: (0),
  setPort: 8000,
  setUser: 'source',
  setPassword: 'MyPassW',
  setMount: '/stream.mp3',
  setName: 'My Stream',
  setGenre: 'Talk, Reggae',
});

The error:
const shout = new Shout();
^
ReferenceError: Shout is not defined

It's Node v14.21.2.

@starapple2
Copy link

That accent (^) is actually pointed at "new".

@VictorQueiroz
Copy link
Collaborator

VictorQueiroz commented Jul 3, 2023

@starapple2 Try this:

const { Shout } = require('libshout');
const s = new Shout();
s.setHost('localhost');
s.setProtocol(0);
s.setPort(8000);
s.setUser('source');
s.setPassword('MyPassW');
s.setMount('/stream.mp3');

Also notice that there is no shout method in the Shout.prototype, so you must read this before using the library.

@starapple2
Copy link

@VictorQueiroz, the error is:
const s = new Shout();
                 ^
TypeError: Shout is not a constructor

@VictorQueiroz
Copy link
Collaborator

VictorQueiroz commented Jul 3, 2023

@starapple2 Try this:

const { Shout } = require('libshout');
const s = new Shout();
s.setHost('localhost');
s.setProtocol(0);
s.setPort(8000);
s.setUser('source');
s.setPassword('MyPassW');
s.setMount('/stream.mp3');

Also notice that there is no shout method in the Shout.prototype, so you must read this before using the library.

@starapple2 Check the require line. It's different.

@starapple2
Copy link

@VictorQueiroz, are you sure? What's the difference? The error message is the same.

@VictorQueiroz
Copy link
Collaborator

@starapple2 Did you try what I suggested?

@starapple2
Copy link

Sorry, I missed what you suggested @VictorQueiroz . Did you mean the usage example? TYhis was the message using that example:
(node:98226) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use node --trace-warnings ... to show where the warning was created)
/home/mark/Applications/abeng/index.js:11
import {Shout} from 'libshout';
^^^^^^

SyntaxError: Cannot use import statement outside a module

@VictorQueiroz
Copy link
Collaborator

VictorQueiroz commented Jul 3, 2023

@starapple2 No. I sent you some code here, please check and let me know. Here: #1 (comment)

@starapple2
Copy link

Ahh. I tried that and posted the error @VictorQueiroz:

const s = new Shout();
                 ^
TypeError: Shout is not a constructor

@VictorQueiroz
Copy link
Collaborator

VictorQueiroz commented Jul 4, 2023

@starapple2 Sorry about the delay. I think the README is wrong, but it should work like that by default, so I will change the behavior to be const {Shout} = require("libshout"). For now you can import it like this:

const Shout = require('libshout');

@starapple2
Copy link

Thanks @VictorQueiroz, you've got it. Now no errors and console says "App listening at http://localhost:3000". I'll now muddle through sending data from the client, amending the code to expect data rather than searching a folder for a file.

@starapple2
Copy link

@VictorQueiroz, do you have an example, or can you write one, of using a playlist? I generate a playlist from files staged for upload and use the file url as their link since JavaScript cannot provide local paths in the file system. I'll work on accessing the mic stream after sorting out a playlist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants