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.
Related
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.
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.
I don't know very much about Java's MIDI function. In fact, it utterly bewilders me. what I'd like to do however is just build a simple application that will play one note.
How to play a single MIDI note using Java Sound?
The support for this out on the web is almost nonexistent, and I am totally at a loss.
I know this is a really old question, but, as a novice programmer, I had a very difficult time figuring out how to do this, so I thought I would share the following hello-world-style program that gets Java to play a single midi note in order to help anyone else getting started.
import javax.sound.midi.*;
public class MidiTest{
public static void main(String[] args) {
try{
/* Create a new Sythesizer and open it. Most of
* the methods you will want to use to expand on this
* example can be found in the Java documentation here:
* https://docs.oracle.com/javase/7/docs/api/javax/sound/midi/Synthesizer.html
*/
Synthesizer midiSynth = MidiSystem.getSynthesizer();
midiSynth.open();
//get and load default instrument and channel lists
Instrument[] instr = midiSynth.getDefaultSoundbank().getInstruments();
MidiChannel[] mChannels = midiSynth.getChannels();
midiSynth.loadInstrument(instr[0]);//load an instrument
mChannels[0].noteOn(60, 100);//On channel 0, play note number 60 with velocity 100
try { Thread.sleep(1000); // wait time in milliseconds to control duration
} catch( InterruptedException e ) {
e.printStackTrace();
}
mChannels[0].noteOff(60);//turn of the note
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
}
}
The above code was primarily created by cutting, pasting, and messing around with code found in several online tutorials. Here are the most helpful tutorials that I found:
http://www.ibm.com/developerworks/library/it/it-0801art38/
This is a great tutorial and probably has everything you are looking for; however, it may be a little overwhelming at first.
http://patater.com/gbaguy/javamidi.htm
Features nonworking code written by a 15 year old. This was - surprisingly - the most helpful thing I found.
Here you go :
MIDI Tag Info on stackoverflow
UnderStanding MIDI
Tutorial on Oracle
Accessing MIDI
MIdi Synthesis
According to my research, Java's sound api does not play well with OsX. It has a hard time determining the active input, so it generally defaults to the first system input.
My solution is to iterate through an array of input ports, recording a couple milliseconds of audio and comparing those pieces. Whichever one has the greatest amplitude, I'll use as my input.
My question is, what would the best method be for generating an array of all input ports available to Java?
You can list all of the available Mixer objects using the following:
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
for (Mixer.Info mixerInfo : mixers){
System.out.println(mixerInfo);
}
On my system, a Mac, this is the result:
Java Sound Audio Engine, version 1.0
Built-in Input, version Unknown Version
Built-in Microphone, version Unknown Version
Edit
Here's how to extract a list of valid Target lines that you can get audio input from:
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
List<Line.Info> availableLines = new ArrayList<Line.Info>();
for (Mixer.Info mixerInfo : mixers){
System.out.println("Found Mixer: " + mixerInfo);
Mixer m = AudioSystem.getMixer(mixerInfo);
Line.Info[] lines = m.getTargetLineInfo();
for (Line.Info li : lines){
System.out.println("Found target line: " + li);
try {
m.open();
availableLines.add(li);
} catch (LineUnavailableException e){
System.out.println("Line unavailable.");
}
}
}
System.out.println("Available lines: " + availableLines);
Once you have the Line.Info object, you can get the TargetDataLine associated with the Line.Info object by calling AudioSystem.getLine() and using that Line.Info as a parameter.
Basics on how to determine what resources are available can be found here:
Accessing Audio System Resources
I found this section to be the most helpful in terms of example code, in the Java Sound tutorials:
http://download.oracle.com/javase/tutorial/sound/converters.html
The tutorial http://download.oracle.com/javase/tutorial/sound/capturing.html
does not cover how to select microphone.
I am enumerating mixers with the following code
System.out.println("Searching for microphones");
for(Mixer.Info mixerinfo : AudioSystem.getMixerInfo()) {
mixer = AudioSystem.getMixer(mixerinfo);
//System.out.println(mixerinfo.toString());
if( mixer.isLineSupported(Port.Info.MICROPHONE) ) {
mixers.add(mixer);
System.out.println(Integer.toString(mixers.size()) + ": " + mixerinfo.toString());
}
}
i.e. by presense of microphone input. But next, having a mixer, I can't get line to read.
If I use mixer.getTargetLineInfo(), I receive an array of one Info, which when passing to mixer.getLine returns an object of type com.sun.media.sound.PortMixer$PortMixerPort, which is not ducumented.
If I use mixer.getTargetLines() I get an empty array.
If I create my own DataLine.Info and pass it to the mixer's getLine, I get unsupported exception.
So, what to do?
Left-field suggestion.
Provide a visual rendering of each sound line, in a component along the lines of the AudioPlotPanel or a simpler RMS volume. It should not take the user too long to figure which sound line they are yodeling through. ;)
I'm trying to do the same thing. I haven't quite found a good solution yet but I can tell you that's not working out because you're trying to get a DataLine from a Port mixer. If and when I figure it out I'll be sure to let you know.