Play sounds with Java on a Mac - java

Alright, before I post any code, here's my specs:
Computer: Macbook Air, Early 2014 model
Java version: Java 8, Update 65 (Java Control Panel says I'm using the recommended version)
OS Version: OS X El Capitan, 10.11.1
Now that that's out of the way, I use Terminal as a Console window, java to run, and javac to compile. I have a class in my project dedicated to playing sounds. The complete code for it is below:
package javacoffeeadventure.audiomanager;
import java.io.*;
import javax.sound.sampled.*;
import javacoffeeadventure.io.FileIO;
import javacoffeeadventure.commandinterpreter.*;
public class AudioManager {
public static void playSound(String soundName) {
try {
FileIO f = new FileIO();
AudioInputStream ain = AudioSystem.getAudioInputStream(f.getURLForResource("sounds/" + soundName));
Clip clip = AudioSystem.getClip();
clip.open(ain);
clip.start();
} catch (Exception ex) {
javacoffeeadventure.commandinterpreter.Console.sharedConsole().error("Exception while playing sound " + soundName + ": " + ex.getMessage());
} finally {
}
}
}
Where...
javacoffeeadventure is the top-level name of the package
commandinterpreter.Console is a way to do stuff quickly with the Console (I had to use the full name because java.io.Console already exists)
javacoffeeadventure.io.FileIO is a simple way to handle resources and load/save a file
I'm playing a wav file
Either way, I'm using javax.sound.sampled.AudioInputStream, javax.sound.sampled.AudioSystem, and javax.sound.sampled.Clip to play sounds.
When invoking clip.start(), the following error occurs:
2015-11-15 21:23:08.195 java[77192:2681680] 21:23:08.195 WARNING: 140: This application, or a library it uses, is using the deprecated Carbon Component Manager for hosting Audio Units. Support for this will be removed in a future release. Also, this makes the host incompatible with version 3 audio units. Please transition to the API's in AudioComponent.h.
This tells me Java uses an obsolete framework, CarbonComponent.h, to play sounds, and OS X suggests Java transition to AudioComponent.h.
Is there a workaround available so I can play sounds without using deprecated methods and avoiding unnecessary exceptions?
Edit
The Java Sound API works, but it outputs this when letting the Jukebox play:
015-11-16 09:23:29.489 java[98123:2879394] 09:23:29.489 WARNING: 140: This application, or a library it uses, is using the deprecated Carbon Component Manager for hosting Audio Units. Support for this will be removed in a future release. Also, this makes the host incompatible with version 3 audio units. Please transition to the API's in AudioComponent.h.
2015-11-16 09:23:40.572 java[98123:2879867] 09:23:40.572 WARNING: 140: This application, or a library it uses, is using the deprecated Carbon Component Manager for hosting Audio Units. Support for this will be removed in a future release. Also, this makes the host incompatible with version 3 audio units. Please transition to the API's in AudioComponent.h.
java.lang.IllegalArgumentException: Unsupported control type: Pan
at com.sun.media.sound.AbstractLine.getControl(AbstractLine.java:150)
at Juke.setPan(Juke.java:435)
at Juke.playSound(Juke.java:302)
at Juke.run(Juke.java:410)
at java.lang.Thread.run(Thread.java:745)
2015-11-16 09:23:54.748 java[98123:2879867] 09:23:54.748 WARNING: 140: This application, or a library it uses, is using the deprecated Carbon Component Manager for hosting Audio Units. Support for this will be removed in a future release. Also, this makes the host incompatible with version 3 audio units. Please transition to the API's in AudioComponent.h.
Unsupported audio file.
2015-11-16 09:24:00.160 java[98123:2879867] 09:24:00.160 WARNING: 140: This application, or a library it uses, is using the deprecated Carbon Component Manager for hosting Audio Units. Support for this will be removed in a future release. Also, this makes the host incompatible with version 3 audio units. Please transition to the API's in AudioComponent.h.
java.lang.IllegalArgumentException: Unsupported control type: Pan
at com.sun.media.sound.AbstractLine.getControl(AbstractLine.java:150)
at Juke.setPan(Juke.java:435)
at Juke.playSound(Juke.java:302)
at Juke.run(Juke.java:410)
at java.lang.Thread.run(Thread.java:745)
2015-11-16 09:24:09.542 java[98123:2879867] 09:24:09.542 WARNING: 140: This application, or a library it uses, is using the deprecated Carbon Component Manager for hosting Audio Units. Support for this will be removed in a future release. Also, this makes the host incompatible with version 3 audio units. Please transition to the API's in AudioComponent.h.

This is because OpenJDK is binding to openal-soft for this and it currently depends on Carbon.
There is an open issue on OpenJDK:
https://bugs.openjdk.java.net/browse/JDK-8138754
It has been fixed in the master branch of openal-soft:
https://github.com/kcat/openal-soft/issues/20
It has not been released as of openal-soft 1.17.0 which is the latest release available as I write this.
It should be possible to build an install a newer openal-soft to fix this. It may be already available in Homebrew.
You can build from source, but I recommend basing your code on the Java Sound API example and documenting this message as a known issue for now as openal-soft has been fixed and its release is outside your control.

Related

How can a containerized JAR (Java) access the default system mixer?

I previously took this question down, it's going back up since it's still a problem we're encountering. We have a JAR that we're resurrecting from three years ago. Back then (before I joined the project), it ran bare-metal (presumably on an RPM-based Linux distribution). Before a developer left, he had containerized it (CentOS7) and left us with very little documentation.
Ultimately, the JAR is calling the function getSourceDataLine() described here: https://docs.oracle.com/javase/7/docs/api/javax/sound/sampled/AudioSystem.html#getSourceDataLine(javax.sound.sampled.AudioFormat)
The returned line will be provided by the default system mixer, or, if not possible, by any other mixer installed in the system that supports a matching SourceDataLine object.
However, the program encounters an IllegalArgumentException
if the system does not support at least one source data line supporting the specified audio format through any installed mixer
java.lang.IllegalArgumentException: No line matching interface SourceDataLine supporting format PCM_SIGNED 8000.0 Hz, 16 bit, stereo, 4 bytes/frame, big-endian is supported.
at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:479)
at javax.sound.sampled.AudioSystem.getSourceDataLine(AudioSystem.java:606)
I inspected the contents of the sound.properties file: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.el7_9.x86_64/jre/lib/sound.properties inside the container and ./jvm/java-1.8.0-openjdk-1.8.0.322.b06-2.el8_5.x86_64/jre/lib/sound.properties on the host. Both are completely commented/empty, so I assume the default system mixer is being used.
In the docker/docker-compose run parameters, I tried adding all capabilities to the Linux container, and that did not resolve the issue (regardless of permissions, I assume the needed sound card device doesn't appear at all).
I suspected there was a --device flag that could be passed to the docker run command (or docker-compose yaml). However, I tried running the container as privileged (access to all host devices), and this did not allow access to a system mixer.
I may try inspecting the devices available to the Java runtime with code similar to here: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4269230
I have heard "audio is difficult in containers". I may try doing full virtualization with QEMU to to try to recreate the host environment, but that seems a little drastic. If anyone has worked with the Java audio system as well as containers and could point me in the right direction, that would be much appreciated.
In Linux accessing the audio devices is all done via the filesystem. So if you mount the necessary files (/dev/audio?) into the container and give suitable privileges you should be good to go.

Java Carbon Component warning on runtime - OS X

I recently learnt how to add sound into a small snake game i am creating. The sound plays when the snake eats the apple. The problem i have is every time the snake eats an apple i get this warning in the cosole (but the program continues to run):
015-10-13 10:00:16.922 java[39731:970632] 10:00:16.922 WARNING: 140: This application, or a library it uses, is using the deprecated Carbon Component Manager for hosting Audio Units. Support for this will be removed in a future release. Also, this makes the host incompatible with version 3 audio units. Please transition to the API's in AudioComponent.h.
What does this mean, and what would i need to do to fix this error?
Here is my method to play the sound:
private static void playSound(File Sound){
try{
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(Sound));
clip.start();
Thread.sleep(clip.getMicrosecondLength()/1000);
}catch(Exception e){
}
}
TL;DR:
This is a console warning intended for the developers in charge of your sound handler, which in this case looks like AudioSystem. Your program should work, but it'll keep throwing these warnings. Are you using an older version of Java? That might explain the issue.
Longform:
I came across this question because I got the same warning (with a different time and process stamp) working with SimpleCV in Python. I did a little digging and I think I can at least elaborate on the issue, if not solve it.
First, this is an Apple-specific issue. The warning we're seeing is actually a console log note, which you can see if you open up your Console and look for the timestamp. The Carbon Component Manager is a deprecated way that Macs handles sound, and is being phased out for a newer way that uses AudioComponent.h.
It looks like AudioSystem is still going about its business the older way. This note is a signal to the developers that they need to update AudioSystem to interface with the new API. It's possible this has already been resolved in newer Java versions. Your program should work fine if you just ignore it, but you could try using a newer Java version to see if that helps.
I'd recommend editing your question to include your system specs and Java version.
More info on Carbon Core Deprecation:
https://developer.apple.com/library/mac/releasenotes/General/CarbonCoreDeprecations/
In case anyone else runs into this from SimpleCV/Python, and for completeness:
I'm running OSX El Capitan on a Macbook Pro (Late 2011), using Python 3.5 and SimpleCV 1.3. My console warning (I'm guessing) stems from the shutter sound that is played when Camera() is used to take a picture in SimpleCV.

mediacodec ExtractMpegFramesTest example mismatch

I tried to run This example from bigflake and I think that there is a mismatch.
they write "ExtractMpegFramesTest.java (requires 4.1, API 16) " so the minimum API required is 16,
but I look over the code and they use "import android.opengl.EGL14;" which required minimum API 17.
Has anyone encountered this problem and succeeded to solve it?(succeeded to save 10 frames on Android 4.1 device)
I've updated the site to have two copies of the source file, one that uses EGL 1.0 and one that uses EGL 1.4. I did a quick test with the SDK, creating an app for API 16, to confirm that it's no longer using post-4.1 APIs. I haven't tried it on an actual device running 4.1 however.
You can use MediaMetadataRetriever.getFrameAtTime in order to extract frames from a video file. It's available since API level 10.

Is it possible to convert android application in eclipse to ios Rim windows using codename one?

I have written an application in eclipse for android and its working fine !!
I would like to send ios Rim and windows build using code name one Is it possible ? or do i have to write the whole code from scratch as a New Codename one project?
I tried directly sending my application using code name send android build but i got error.
Error log
[javac] C:\Documents and Settings\0mkar\My Documents\Downloads\Compressed\android\android\src\com\android\Log_SC.java:3: error: cannot find symbol
[javac] import java.io.BufferedWriter;
[javac] ^
[javac] symbol: class BufferedWriter
Full Error log
http://www.mediafire.com/?evb4ex8lg8054ja
Yes but you will need to adapt your code to use Codename One features only and need to rewrite your UI/networking code. E.g. BufferedWriter isn't supported however all streams are buffered so you don't need to buffer anything and the Writer/OutputStreamWriter are supported. This requires some effort, I don't want to discount that but its still way easier than porting to all these platforms manually.
The reasoning behind this is to maximize portability, the larger the API the more bugs and the larger the resulting applications would be when shipped on a platform that doesn't have a compatible VM (e.g. iOS or Windows Phone). It also slows down build times (more class lookups etc.).
The nice thing is that we try to help when you get stuck and if something important is missing its really easy to add both yourself (the project is open source and got a lot of contributions from 3rd parties) and by asking us.

FreeTTS, Java, Linux: Workaround for "LINE UNAVAILABLE: Format is ..."

When I run FreeTTS examples, I get this error:
LINE UNAVAILABLE: Format is pcm_signed 16000.0 Hz 16 bits 1 channel big endian
In this post, Freetts problem in Java
someone claims it's a known Linux/Java sound bug and has a workaround,
linking to http://forums.sun.com/thread.jspa?threadID=5189363 .
But this link does not work anymore since Oracle screwed it.
Archive.org seems not to have this page archived.
Does anyone have the workaround / patch for FreeTTS?
Thanks,
Ondra
Linux's ALSA is one large, complex API. OpenJDK and Sun's JDK seem to use it differently. Most modern Linux distributions also use PulseAudio, which virtualizes ALSA so that all audio goes through PulseAudio for software mixing before going to ALSA for playback.
When nothing is accessing the sound card, and Java is the only user, it tends to work. However when something else has the sound card open, Java apps quickly break with both your error and "javax.sound.sampled.LineUnavailableException: Audio Device Unavailable".
One potential workaround is to enumerate all mixers in the system with AudioSystem.getMixerInfo(), then try to open the line with AudioSystem.getSourceDataLine(format, mixerInfo) for the mixers you want. Some will work better than others. In particular the "Java Sound Audio Engine" and the "default [default]" mixers, if they exist, tend to work.
The only solution if you don't want to modify the FreeTTS source code though, is to install pulse-java. This registers a special PulseAudio sound provider, which bypasses the ALSA virtualization and goes directly to PulseAudio. Ubuntu installs this as part of its OpenJDK package.
Someone should really patch Java Sound to play with ALSA in a friendlier way. For one ALSA device names should be prefixed with plug: to get ALSA to convert sound formats and sample rates on the fly. And the other rules for safe ALSA subset should also be followed.
Hmm, I had better luck googling after asking the question, so...:
http://workorhobby.blogspot.com/2011/02/java-audio-freetts-line-unavailable.html
A big thanks to the author.
Update: Actually, this is not a nice workaround since it will keep FreeTTS on hold until the line is free.
FWIU, the mentioned patch had better solution - not demanding exclusive access or such.
Update: I've compiled a FreeTTS troubleshooting page.
A program based on FreeTTS, the free text-to-speech engine for Java, was getting occasional errors
"LINE UNAVAILABLE: Format is ..."
Turns out there is no Java Exception or other mechanism to detect this error that occurs inside the FreeTTS library. All you get is the message on System.out, so there is no good way to react programatically.
Workaround: Configure the FreeTTS audio player to attempt accessing the audio device more than once until it succeeds. In this example, a short delay of 0.1 seconds is used to not miss an opportunity to grab the audio device; we keep trying for 30 seconds:
System.setProperty("com.sun.speech.freetts.audio.AudioPlayer.openFailDelayMs", "100");
System.setProperty("com.sun.speech.freetts.audio.AudioPlayer.totalOpenFailDelayMs", "30000");
If the audio device is permanently used by another program, there is of course no way to get access. Under Linux, this command will display the ID of the process that is currently holding the audio device, so you can then try to get rid of the offending program:
/sbin/fuser /dev/dsp
Regarding the link screwed by Oracle - given that older SO answer you refer mentions horrendous java linux sound bug that is still not fixed and suggests to check the third post, it is likely that lost thread was migrated to:
https://forums.oracle.com/forums/thread.jspa?threadID=2206163
above thread starts with reference to JMF Bug 4352921 at http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4352921_
third post in the thread says "Yes, according to the API docs it's a "catastrophic" error from which no player can return safely. Which is why it's so strange to be able to trigger it so easily..."
workaround to the problem discussed is described in the sixth post as follows:
I stumbled upon a blog post that suggested that Java needs to be told to use the OSS libraries as it's not yet up to ALSA. The command to use was "padsp" which forces the application to use OSS. So if I call "padsp jmstudio", it now plays and mixes the audio just fine. I tried it with my application also, which prefetches a number of players in the same JVM, and they all prefetched perfectly. So it would seem, for now, JMF applications on Linux may need to be called through padsp.

Categories