diff --git a/src/native/ffmpeg/README b/src/native/ffmpeg/README index a7e4e7abc51cc76b91b57217e46161a9164b49df..8e9bc91daa08fc55fc72e01b7021d6165ce32034 100644 --- a/src/native/ffmpeg/README +++ b/src/native/ffmpeg/README @@ -45,6 +45,12 @@ patch -Np1 -i x264-01-freebsd.patch ./configure --enable-pic +- For android +NDK_BASE=/../android-ndk-r8c +./configure --enable-pic --host=arm-linux --disable-asm \ + --sysroot="$NDK_BASE/platforms/android-9/arch-arm/" \ + --cross-prefix=$NDK_BASE/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi- + 3. ffmpeg patch -Np1 -i ffmpeg-01-libavcodec_libx264.c-zero_latency.patch @@ -82,6 +88,13 @@ Add the following to the configure line: Add the following to the configure line: --enable-pic --enable-pthreads --enable-memalign-hack +- For android remove lame and add + --arch=arm \ + --target-os=linux \ + --enable-runtime-cpudetect \ + --sysroot="$NDK_BASE/platforms/android-9/arch-arm/" \ + --cross-prefix=$NDK_BASE/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi- + 4. jnffmpeg Define the environment variable JAVA_HOME so that the JNI headers can be found. diff --git a/src/org/jitsi/impl/libjitsi/LibJitsiImpl.java b/src/org/jitsi/impl/libjitsi/LibJitsiImpl.java index 30118303c127a215446574bc73ac281776cccbc7..2f7615fd7d0cc3d1f8890328fd2633d022892a50 100644 --- a/src/org/jitsi/impl/libjitsi/LibJitsiImpl.java +++ b/src/org/jitsi/impl/libjitsi/LibJitsiImpl.java @@ -155,7 +155,7 @@ else if (logger.isInfoEnabled()) logger.info( "Failed to initialize service implementation " + serviceImplClassName - + ". Will continue without it."); + + ". Will continue without it.", exception); } return service; diff --git a/src/org/jitsi/impl/neomedia/codec/video/h264/DePacketizer.java b/src/org/jitsi/impl/neomedia/codec/video/h264/DePacketizer.java index a6010103babd994252e923d5905cc7773865e0dc..8e6651265f35105be31009230c7e7aeb73ad9fa9 100644 --- a/src/org/jitsi/impl/neomedia/codec/video/h264/DePacketizer.java +++ b/src/org/jitsi/impl/neomedia/codec/video/h264/DePacketizer.java @@ -46,7 +46,7 @@ public class DePacketizer * structure contains the first NAL unit of an access unit in decoding * order". */ - private static final byte[] NAL_PREFIX = { 0, 0, 1 }; + public static final byte[] NAL_PREFIX = { 0, 0, 1 }; /** * The indicator which determines whether incomplete NAL units are output diff --git a/src/org/jitsi/impl/neomedia/device/AudioSystem.java b/src/org/jitsi/impl/neomedia/device/AudioSystem.java index f495ac0a7139f3554b7f8279cd0b2231f430e766..fade77f7e0beffecd2d2a50c60786438103e6096 100644 --- a/src/org/jitsi/impl/neomedia/device/AudioSystem.java +++ b/src/org/jitsi/impl/neomedia/device/AudioSystem.java @@ -6,9 +6,17 @@ */ package org.jitsi.impl.neomedia.device; +import java.io.*; +import java.net.*; import java.util.*; +import org.jitsi.service.libjitsi.*; import org.jitsi.service.neomedia.*; +import org.jitsi.service.resources.*; +import org.jitsi.util.*; + +import javax.media.*; +import javax.sound.sampled.*; /** * Represents a <tt>DeviceSystem</tt> which provides support for the devices to @@ -59,6 +67,11 @@ public abstract class AudioSystem public static final String LOCATOR_PROTOCOL_PULSEAUDIO = "pulseaudio"; + /** + * The <tt>Logger</tt> used by this instance for logging output. + */ + private static Logger logger = Logger.getLogger(AudioSystem.class); + public static AudioSystem getAudioSystem(String locatorProtocol) { AudioSystem[] audioSystems = getAudioSystems(); @@ -317,4 +330,66 @@ public void propertyChange( { firePropertyChange(property, oldValue, newValue); } + + /** + * Obtains an audio input stream from the URL provided. + * @param uri a valid uri to a sound resource. + * @return the input stream to audio data. + * @throws IOException if an I/O exception occurs + */ + public InputStream getAudioInputStream(String uri) + throws IOException + { + AudioInputStream audioStream = null; + + ResourceManagementService resources + = LibJitsi.getResourceManagementService(); + URL url + = (resources == null) + ? null + : resources.getSoundURLForPath(uri); + + try + { + if (url == null) + { + // Not found by the class loader. Perhaps it's a local file. + url = new URL(uri); + } + + audioStream = javax.sound.sampled.AudioSystem + .getAudioInputStream(url); + } + catch (MalformedURLException e) + { + return null; + } + catch (UnsupportedAudioFileException uafex) + { + logger.error("Unsupported format of audio stream " + url, uafex); + } + + return audioStream; + } + + /** + * Returns the audio format for the <tt>InputStream</tt>. Or null + * if format cannot be obtained. + * @param audioInputStream the input stream. + * @return the format of the audio stream. + */ + public Format getFormat(InputStream audioInputStream) + { + if(!(audioInputStream instanceof AudioInputStream)) + return null; + + AudioFormat audioStreamFormat = + ((AudioInputStream)audioInputStream).getFormat(); + + return new javax.media.format.AudioFormat( + javax.media.format.AudioFormat.LINEAR, + audioStreamFormat.getSampleRate(), + audioStreamFormat.getSampleSizeInBits(), + audioStreamFormat.getChannels()); + } } diff --git a/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java b/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java index bba9a8a5f9660e5639191115d9b51f3da2738f7b..d41bce55c6d72646ac06f095d57f7a99cf30dc32 100644 --- a/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java +++ b/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java @@ -66,8 +66,8 @@ public class DeviceConfiguration private static final String[] CUSTOM_RENDERERS = new String[] { - OSUtils.IS_ANDROID ? "net.java.sip.communicator.impl.neomedia.jmfext.media.renderer.audio.AudioTrackRenderer" : null, - OSUtils.IS_ANDROID ? "net.java.sip.communicator.impl.neomedia.jmfext.media.renderer.audio.OpenSLESRenderer" : null, + OSUtils.IS_ANDROID ? "org.jitsi.impl.neomedia.jmfext.media.renderer.audio.AudioTrackRenderer" : null, + OSUtils.IS_ANDROID ? "org.jitsi.impl.neomedia.jmfext.media.renderer.audio.OpenSLESRenderer" : null, OSUtils.IS_LINUX ? ".audio.PulseAudioRenderer" : null, OSUtils.IS_ANDROID ? null : ".audio.PortAudioRenderer", "net.java.sip.communicator.impl.neomedia.jmfext.media.renderer.video.JAWTRenderer" diff --git a/src/org/jitsi/impl/neomedia/notify/AudioNotifierServiceImpl.java b/src/org/jitsi/impl/neomedia/notify/AudioNotifierServiceImpl.java index 27d4fa1c41ab10525ea4c779983b9f47b6ae198b..574716fbd4b4d33c2496fef721ce2dcab8e61e3f 100644 --- a/src/org/jitsi/impl/neomedia/notify/AudioNotifierServiceImpl.java +++ b/src/org/jitsi/impl/neomedia/notify/AudioNotifierServiceImpl.java @@ -124,26 +124,6 @@ public SCAudioClip createAudio(String uri, boolean playback) if (audio == null) { - ResourceManagementService resources - = LibJitsi.getResourceManagementService(); - URL url - = (resources == null) - ? null - : resources.getSoundURLForPath(uri); - - if (url == null) - { - // Not found by the class loader. Perhaps it's a local file. - try - { - url = new URL(uri); - } - catch (MalformedURLException e) - { - return null; - } - } - try { AudioSystem audioSystem @@ -151,7 +131,7 @@ public SCAudioClip createAudio(String uri, boolean playback) if (audioSystem == null) { - audio = new JavaSoundClipImpl(url, this); + audio = new JavaSoundClipImpl(uri, this); } else if (NoneAudioSystem.LOCATOR_PROTOCOL.equalsIgnoreCase( audioSystem.getLocatorProtocol())) @@ -162,7 +142,7 @@ else if (NoneAudioSystem.LOCATOR_PROTOCOL.equalsIgnoreCase( { audio = new AudioSystemClipImpl( - url, + uri, this, audioSystem, playback); diff --git a/src/org/jitsi/impl/neomedia/notify/AudioSystemClipImpl.java b/src/org/jitsi/impl/neomedia/notify/AudioSystemClipImpl.java index c5be2d527d87495395a1b546e888a9bba5d58493..4ab84310d353c5d9712684b9670c8302faaa80c4 100644 --- a/src/org/jitsi/impl/neomedia/notify/AudioSystemClipImpl.java +++ b/src/org/jitsi/impl/neomedia/notify/AudioSystemClipImpl.java @@ -7,12 +7,11 @@ package org.jitsi.impl.neomedia.notify; import java.io.*; -import java.net.*; import javax.media.*; -import javax.sound.sampled.*; import org.jitsi.impl.neomedia.codec.audio.speex.*; +import org.jitsi.impl.neomedia.device.*; import org.jitsi.service.audionotifier.*; import org.jitsi.util.*; @@ -32,8 +31,7 @@ public class AudioSystemClipImpl private static final Logger logger = Logger.getLogger(AudioSystemClipImpl.class); - private final org.jitsi.impl.neomedia.device.AudioSystem - audioSystem; + private final AudioSystem audioSystem; private Buffer buffer; @@ -53,9 +51,9 @@ public class AudioSystemClipImpl * @throws IOException cannot audio clip with supplied URL. */ public AudioSystemClipImpl( - URL url, + String url, AudioNotifierService audioNotifier, - org.jitsi.impl.neomedia.device.AudioSystem audioSystem, + AudioSystem audioSystem, boolean playback) throws IOException { @@ -107,20 +105,17 @@ protected void exitRunOnceInPlayThread() protected boolean runOnceInPlayThread() { - AudioInputStream audioStream = null; + InputStream audioStream = null; try { - audioStream = AudioSystem.getAudioInputStream(url); + audioStream = audioSystem.getAudioInputStream(uri); } catch (IOException ioex) { - logger.error("Failed to get audio stream " + url, ioex); - } - catch (UnsupportedAudioFileException uafex) - { - logger.error("Unsupported format of audio stream " + url, uafex); + logger.error("Failed to get audio stream " + uri, ioex); } + if (audioStream == null) return false; @@ -128,13 +123,13 @@ protected boolean runOnceInPlayThread() try { - AudioFormat audioStreamFormat = audioStream.getFormat(); - Format rendererFormat - = new javax.media.format.AudioFormat( - javax.media.format.AudioFormat.LINEAR, - audioStreamFormat.getSampleRate(), - audioStreamFormat.getSampleSizeInBits(), - audioStreamFormat.getChannels()); + Format rendererFormat = audioSystem.getFormat(audioStream); + + if(rendererFormat == null) + { + return false; + } + Format resamplerFormat = null; if (renderer.setInputFormat(rendererFormat) == null) @@ -215,7 +210,7 @@ protected boolean runOnceInPlayThread() } catch (IOException ioex) { - logger.error("Failed to read from audio stream " + url, ioex); + logger.error("Failed to read from audio stream " + uri, ioex); return false; } catch (ResourceUnavailableException ruex) diff --git a/src/org/jitsi/impl/neomedia/notify/JavaSoundClipImpl.java b/src/org/jitsi/impl/neomedia/notify/JavaSoundClipImpl.java index dc67a062032b6fa0356a055347c24185433248c5..7e333f816e5389b1fa8c3c2f2490fb7ff484ca30 100644 --- a/src/org/jitsi/impl/neomedia/notify/JavaSoundClipImpl.java +++ b/src/org/jitsi/impl/neomedia/notify/JavaSoundClipImpl.java @@ -101,7 +101,7 @@ public Constructor<AudioClip> run() * audio stored at a specific <tt>URL</tt> using * <tt>java.applet.AudioClip</tt>. * - * @param url the <tt>URL</tt> at which the audio is stored and which the + * @param uri the <tt>URL</tt> at which the audio is stored and which the * new instance is to load * @param audioNotifier the <tt>AudioNotifierService</tt> which is * initializing the new instance and whose <tt>mute</tt> property/state is @@ -109,12 +109,12 @@ public Constructor<AudioClip> run() * @throws IOException if a <tt>java.applet.AudioClip</tt> could not be * initialized or the audio at the specified <tt>url</tt> could not be read */ - public JavaSoundClipImpl(URL url, AudioNotifierService audioNotifier) + public JavaSoundClipImpl(String uri, AudioNotifierService audioNotifier) throws IOException { - super(url, audioNotifier); + super(uri, audioNotifier); - audioClip = createAppletAudioClip(url.openStream()); + audioClip = createAppletAudioClip(new URL(uri).openStream()); } /** diff --git a/src/org/jitsi/service/audionotifier/AbstractSCAudioClip.java b/src/org/jitsi/service/audionotifier/AbstractSCAudioClip.java index b2d48e0e6406c2a2ca1eb2277ca08a98031b547d..5d484612f621675e119eb35b34fe979bb507ae72 100644 --- a/src/org/jitsi/service/audionotifier/AbstractSCAudioClip.java +++ b/src/org/jitsi/service/audionotifier/AbstractSCAudioClip.java @@ -70,17 +70,17 @@ public abstract class AbstractSCAudioClip private final Object sync = new Object(); /** - * The <tt>URL</tt> of the audio to be played by this instance. + * The <tt>String</tt> uri of the audio to be played by this instance. * <tt>AbstractSCAudioClip</tt> does not use it and just remembers it in * order to make it available to extenders. */ - protected final URL url; + protected final String uri; protected AbstractSCAudioClip( - URL url, + String uri, AudioNotifierService audioNotifier) { - this.url = url; + this.uri = uri; this.audioNotifier = audioNotifier; } @@ -201,7 +201,7 @@ public boolean isInvalid() /** * Determines whether this instance plays the audio it represents in a loop. * - * @param <tt>true</tt> if this instance plays the audio it represents in a + * @return <tt>true</tt> if this instance plays the audio it represents in a * loop; <tt>false</tt>, otherwise */ public boolean isLooping() @@ -500,8 +500,8 @@ public void setInvalid(boolean invalid) * instance and the <tt>loopInterval</tt> and <tt>loopCondition</tt> * parameters of {@link #play(int, Callable)} anyway. * - * @param <tt>true</tt> to mark this instance that it should play the audio - * it represents in a loop; otherwise, <tt>false</tt> + * @param looping <tt>true</tt> to mark this instance that it should play + * the audio it represents in a loop; otherwise, <tt>false</tt> */ public void setLooping(boolean looping) { diff --git a/src/org/jitsi/service/neomedia/codec/Constants.java b/src/org/jitsi/service/neomedia/codec/Constants.java index a49ea44709a84d7ebb2b336abdcdd4d9e407fcbe..1c1e7743bca08988f33c8a76d08b2bde5a8bb907 100644 --- a/src/org/jitsi/service/neomedia/codec/Constants.java +++ b/src/org/jitsi/service/neomedia/codec/Constants.java @@ -94,6 +94,13 @@ public class Constants */ public static final String TELEPHONE_EVENT = "telephone-event"; + /** + * The list of well-known sample rates of audio data used throughout + * neomedia. + */ + public static final double[] AUDIO_SAMPLE_RATES + = { 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 }; + /** * mode : Frame size for the encoding/decoding * 20 - 20 ms