Java. Linux. Multiple soundcards order - java

I wrote spring boot application for capturing audio from three the same soundcards, converting sound to mp3 and stream it to network.
Code for getting available devices:
public static Map<Integer, Mixer.Info> getAvailableDevices() {
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
Map<Integer, Mixer.Info> devices = new HashMap<>();
for (Mixer.Info mixer : mixers) {
Integer patternStart = mixer.getName().indexOf(ALSA_DEVICE_PATTERN);
if (patternStart > 0) {
devices.put(Integer.parseInt(mixer.getName().substring(patternStart + 4, patternStart + 5)), mixer);
}
}
return devices;
}
My application started like linux demon after reboot. Also I need to restart capture when computer was rebooted. And there is a trouble. In linux soundcards get random order when computer is booting.
Way #1: Hard binding soundcards by serial number or else. But Mixer.Info don't contains information about serial number or anything else for hard binding. All devices have the same info.
Way #2: Hard binding soundcards in /etc/modprode.d/alsa-base for having the same cards order in system ever. But soundcards have the same kernel module also. Something like this:
options snd_ca0106 index=0
options snd_ca0106 index=1
options snd_ca0106 index=2
I can't guarantee that there will be the same order of devices after the reboot.
I don't know how I can do it. Help me, please.

Related

How do I pass multiple types of data over a serial port connection using JSSC?

I am tasked with creating a program that can initiate a payment on an Ingenico card terminal. It is a smaller part to a larger project to create a custom P.O.S system for a business. But I am facing a variety of road blocks making this problem difficult.
I have no experience in programming with serial ports. The documentation I have found online only depicts writing strings or bytes. The examples are simple but do not tell me enough information.
There is no documentation for the device I am using. Ingenico does not provide this information. The only way I have been able to figure out what data the card reader is expecting to initiate a payment is via this already completed project on github. Here is the link
https://github.com/Ousret/pyTeliumManager
This implementation is in python, and is using a linux-based system. We would be using this but we need a more custom implementation, hence why I am doing this in java.
I have looked and looked in this project to find how the data is structured and then sent over the serial port connection, but at this point I am missing it out of ignorance. I'm not familiar with python at all and the only thing I know is that the data to initiate a payment is as follows...
a float for the transaction amount
three strings, one for the currency type (USD, EUR etc) payment method (card) and the checkout ID (which can be anything, this is for personal book keeping)
and three booleans, one if you would like to wait for the transaction to be approved, one if you would like bank verification and one if you would like the payees payment information saved. (Ive set all these to false as they're not necessary at this moment. I am just trying to write something that works as a proof of concept before building an interface)
Now, here's some of my test code, and most of this is similar to what I've found on the internet through my research.
public static void main(String[] args) {
SerialPort cerealPort = new SerialPort("COM9");
try {
System.out.println("Port opened: " + cerealPort.openPort());
System.out.println("reading bytes " + cerealPort.readBytes());
System.out.println("name " + cerealPort.getPortName());
cerealPort.writeString("bing bong");
//cerealPort.setEventsMask(256);
System.out.println("Params setted: " + cerealPort.setParams(9600, 8, 1, 0));
System.out.println("\"Hello World!!!\" successfully writen to port: " + cerealPort.writeBytes("Hello World!!!".getBytes()));
System.out.println("Port closed: " + cerealPort.closePort());
}
catch (SerialPortException ex){
System.out.println(ex);
}
}
}
This code really doesn't really do anything and was just to test that communication with the device is working properly. Note that nothing happens on the terminal when this code is run.
Now I have this class called TelliumData, which has the data members I described.
public class TelliumData {
float amount;
String paymentMode = "debit";
String currency = "USD";
String checkoutId = "1";
boolean transactionWait = false; // waits for trans to end. Set to True if you need valid transaction status otherwise, set it to False.
boolean collectPaymentInfo = false;
boolean forceBankVerify = false;
}
I have 0 idea how to pass this information to the terminal using the functions in JSSC
My question is, at its core, how to I send this data over a serial port?
I have tried using .writebytes and .writeint to send over all data one by one but this doesn't do anything and doesn't trigger a payment initialization on the card reader.
I don't understand how the python implementation has done it either. It would be great if someone could explain how that data is packaged and sent.

Android BLE. Is it possible to use a regex as a filter to scan for Mac Address?

I have to build an App that scans for BLE devices, and return it's data.
The devices won't show on scan, unless I use a filter.
UUID is not an option, and the device does not broadcast it's name (It shows N/A when scanned with nrfConnect.
I am trying to scan it by MAC Address. BUT, I do not know the MAC Addresses, since it can be any device of it's kind, so the App won't previously know the MAC Address of the device.
I already know that the device have a prefix on it's Address which is F8:36:9B. The thing is the suffix. How can I (and if it is possible to) make a regex to pass as a parameter to find all possible matches of the Device MAC Address?
The regex per se, I have, ([A-Fa-f0-9]{2}:){2}[A-Fa-f0-9]{2}, which I got from Android Bluetooth ScanFilter Partial String Matching.
I just don't know how to implement it on the scanFilter.
ScanFilter filterMac = new ScanFilter.Builder().setDeviceAddress(/**THE_SUFIX_AND_REGEX*/).build();
Is it possible? If it is, then how?
Everything I tried, I get this error:
Error: invalid device address
I have tried generating all the possible matches using for loops and saving it to an ArrayList, and then adding it to the list of filters, but I get an OutOfMemoryException, since the result is over 16million possibilities.
Not possible with filters. You must filter yourself...like you did already
After a lot of struggle, I found a solution to my problem.
It does not answer the question per se, i.e. if it's possible to use a regex as a filter to scan for MAC Address.
But, I managed to properly scan for the devices I needed.
This is what I did:
First of all, I made a filter by name. Yes, name, the device have no name. So I had to think... What if, I filter by name, to scan for devices whose name == null?
private List<ScanFilter> scanFilters() {
List<ScanFilter> list = new ArrayList<ScanFilter>();
ScanFilter scanFilterName = new ScanFilter.Builder().setDeviceName(null).build();
list.add(scanFilterName);
return list;
}
Well, it worked! But, it returned me not only the devices I needed, but tons of other devices, alongside with them. It was a mess in my scan, so how to refine the filter to give me only those ones I needed?
The second filter (which wasn't on the scanFilters()method above, it was on the scanResult), was by MAC Address prefix (which is the same for my devices).
private Set<String> btDevice = new LinkedHashSet<String>();
private ScanCallback scanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
ScanRecord record = result.getScanRecord();
byte[] dataByteArray = record.getBytes();
if (device.getAddress().startsWith("F8:36:9B")) {
btDevice.add(device.getAddress());
}
}
};
And voilá, I got a scan with only the devices I needed.
I still want to know if the main question is possible, i.e. if we can use a regex on the scanFilter(), to filter a range of something (in this case, MAC Address). So, if someone have a solution to this, please feel free to answer.
Thanks!

Streaming Desktop in VLCJ

I'm trying to write a Java program which allows one user to act as a server and stream their desktop (video & audio), then other users act as clients and watch the live stream of their desktop (similar to Twitch, Webex, Skype screenshare, etc). I am using VLCJ for this, although I have no commitment to using it so if there is a better solution I'm all ears. Here is the code, which is copied from the link I provide below:
package test.java;
import uk.co.caprica.vlcj.discovery.NativeDiscovery;
import uk.co.caprica.vlcj.player.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.headless.HeadlessMediaPlayer;
import test.java.VlcjTest;
/**
* An example of how to stream a media file over HTTP.
* <p>
* The client specifies an MRL of <code>http://127.0.0.1:5555</code>
*/
public class StreamHttp extends VlcjTest {
//when running this it requires an MRL (Media Resource Locator)
//fancy term for saying the file you want to stream. This could be a url to another
//location that streams media or a filepath to a media file you want to stream
//on the system you are running this code on.
public static void main(String[] args) throws Exception {
new NativeDiscovery().discover();
if(args.length != 1) {
System.out.println("Specify a single MRL to stream");
System.exit(1);
}
//the media you are wanting to stream
String media = args[0];
//this is the IP address and port you are wanting to stream at
//this means clients will connect to http://127.0.0.1:5555
//to watch the stream
String options = formatHttpStream("127.0.0.1", 5555);
System.out.println("Streaming '" + media + "' to '" + options + "'");
//this creates a the actual media player that will make calls into the native
//vlc libraries to actually play the media you supplied. It does it in
//a headless fashion, as you are going to stream it over http to be watched
//instead of playing it locally to be watched.
MediaPlayerFactory mediaPlayerFactory = new MediaPlayerFactory(args);
HeadlessMediaPlayer mediaPlayer = mediaPlayerFactory.newHeadlessMediaPlayer();
//this simply starts the player playing the media you gave it
mediaPlayer.playMedia(media, options);
// Don't exit
//basically you don't want the thread to end and kill the player,
//so it just hangs around and waits for it to end.
Thread.currentThread().join();
}
private static String formatHttpStream(String serverAddress, int serverPort) {
StringBuilder sb = new StringBuilder(60);
sb.append(":sout=#duplicate{dst=std{access=http,mux=ts,");
sb.append("dst=");
sb.append(serverAddress);
sb.append(':');
sb.append(serverPort);
sb.append("}}");
return sb.toString();
}
}
I pass "screen://" as a parameter to this program. When I run the code, I get this error message:
[000000000038b250] access_output_http access out: Consider passing --http-host=IP on the command line instead.
[000000001ccaa220] core mux error: cannot add this stream
[000000001cc72100] core decoder error: cannot create packetizer output (RV32)
I tried searching for a solution but all I could find was this:
Video Streaming in vlcj
and although this user had the same error, I couldn't solve my problem from this link, although I did use the StreamHttp code sample from it. I am a relatively inexperienced programmer so if I missed an obvious solution then I apologize. I am using Java 1.8, Windows 7 64 bit.
You need something like this:
String media = "screen://";
String[] options = {
":sout=#transcode{vcodec=FLV1,vb=4096,scale=0.500000}:http{mux=ffmpeg{mux=flv},dst=:5000/"
};
The key things shown here are a "sout" string to transcode the video, then another appended "sout" string to stream (in this case via http).
In this example string, for http streaming only the port (5000, arbitrarily chosen) is specified. No host is specified, so it means localhost. You could have something like "dst=127.0.0.1:8080/" or whatever you need.
You will have to choose/experiment with the specific transcoding/streaming options that you want. There is no one size fits all for those options.
Foot-note:
You can actually use VLC itself to generate this string for you.
Start VLC, then choose the media you want to play.
Instead of pressing "Play", use the widget to select "Stream" instead. This opens the Streaming wizard where you can pick all of your options.
At the end of the wizard, before you start playing, it shows you the string you need.

Java: How do I get a unique serial ID for the computer that will never change

I am making a program that requires a unique serial ID for the computer that is running the program. It needs to never change (or change very rarely AND the user has to know when it will change in advance). Also I need it to either work on Linux, Mac and Windows (maybe even Solaris) or one way for each.
I have tried this...
try
{
Process process = Runtime.getRuntime().exec(new String[]
{
"wmic", "bios", "get", "serialnumber"
});
process.getOutputStream().close();
Scanner sc = new Scanner(process.getInputStream());
String property = sc.next();
String serial = sc.next();
System.out.println(property + ": " + serial);
} catch(IOException e)
{
e.printStackTrace();
}
but WMIC is only on windows. But other than that, it's perfect.
Just a way to do that on a Mac and in Linux would be perfect
There is no computer serial number, even if there were, the client's software could be modified to send any number. You could somehow incorporate the network card's media access control address (MAC address), but that can be altered by software, or the card could be swapped out, or there could be multiple cards.
About the only thing you can do for a voting application is to use secure hardware that contains a unique number that can't be copied coupled with encryption. This is what smartcards do.

Change Mixer to output sound to in java

I am trying to play a wav/mp3 to my virtual audio cable, I have been searching for hours but can't seem to find how to achieve this. I have been able to play sound in both formats but I can't get it to output to 'Line-1' rather than 'Speakers'
Any helpful links or example code would be greatly appreciated.
To get an array of all Mixers on the current platform, you may use AudioSystem#getMixerInfo:
static void printAllMixerNames() {
for(Mixer.Info info : AudioSystem.getMixerInfo()) {
System.out.println(info.getName());
}
}
If your virtual cable is available, it will be in the array. For example, on my Mac the following is printed:
Java Sound Audio Engine
Built-in Input
Soundflower (2ch)
Soundflower (64ch)
Pro Tools Aggregate I/O
(Soundflower is a virtual device.)
To get some specific Mixer you unfortunately need to do String evaluation. So you need to discover its name, vendor, whatever, beforehand or give the user an option to pick one from a list.
static Mixer getMixerByName(String toFind) {
for(Mixer.Info info : AudioSystem.getMixerInfo()) {
if(toFind.equals(info.getName())) {
return AudioSystem.getMixer(info);
}
}
return null;
}
Once you have a particular Mixer you can obtain a Line or AudioInputStream from it. You can obtain a Clip from it through AudioSystem#getClip(Mixer.Info).
I am trying to play a wav/mp3...
javax.sound.sampled does not support mp3. Alternatives can be found here.

Categories

Resources