summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChia-chi Yeh <chiachi@android.com>2010-08-06 17:24:20 +0800
committerChia-chi Yeh <chiachi@android.com>2010-08-06 17:24:20 +0800
commit9c0e76beae15ce3ef27507b6b32a75ab78c6b836 (patch)
tree00702c7c5d6e9dbbe9664d2d927fad1fc02ed330
parent29c26d07eb1c66891e6ad4f0396712f0a1273c92 (diff)
downloadnist-sip-9c0e76beae15ce3ef27507b6b32a75ab78c6b836.tar.gz
RTP: remove dead code. Now we are officially in the frameworks.
Change-Id: I772d47805b982ead28cec53dda7a8acdd308a407
-rw-r--r--src/android/net/rtp/AudioCodec.java55
-rw-r--r--src/android/net/rtp/AudioGroup.java90
-rw-r--r--src/android/net/rtp/AudioStream.java135
-rw-r--r--src/android/net/rtp/RtpStream.java172
-rw-r--r--src/com/android/sip/rtp/AudioCodec.java55
-rw-r--r--src/com/android/sip/rtp/AudioStream.java188
-rw-r--r--src/com/android/sip/rtp/RtpSocket.java118
-rw-r--r--src/jni/rtp/Android.mk43
-rw-r--r--src/jni/rtp/AudioCodec.h58
-rw-r--r--src/jni/rtp/AudioStream.cpp660
-rw-r--r--src/jni/rtp/G711Codec.cpp96
-rw-r--r--src/jni/rtp/RtpSocket.cpp254
-rw-r--r--src/jni/rtp/RtpSocket.h35
-rw-r--r--src/jni/rtp/libsiprtp.cpp33
-rw-r--r--src/jni/rtp_jni/Android.mk44
-rw-r--r--src/jni/rtp_jni/AudioCodec.cpp161
-rw-r--r--src/jni/rtp_jni/AudioCodec.h36
-rw-r--r--src/jni/rtp_jni/AudioGroup.cpp1004
-rw-r--r--src/jni/rtp_jni/RtpStream.cpp126
-rw-r--r--src/jni/rtp_jni/rtp_jni.cpp32
-rw-r--r--src/jni/rtp_jni/util.cpp61
21 files changed, 0 insertions, 3456 deletions
diff --git a/src/android/net/rtp/AudioCodec.java b/src/android/net/rtp/AudioCodec.java
deleted file mode 100644
index 242ad58..0000000
--- a/src/android/net/rtp/AudioCodec.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.rtp;
-
-public class AudioCodec {
- public static final AudioCodec ULAW = new AudioCodec("PCMU", 8000, 160, 0);
- public static final AudioCodec ALAW = new AudioCodec("PCMA", 8000, 160, 8);
-
- /**
- * Returns system supported codecs.
- */
- public static AudioCodec[] getSystemSupportedCodecs() {
- return new AudioCodec[] {AudioCodec.ULAW, AudioCodec.ALAW};
- }
-
- /**
- * Returns the codec instance if it is supported by the system.
- *
- * @param name name of the codec
- * @return the matched codec or null if the codec name is not supported by
- * the system
- */
- public static AudioCodec getSystemSupportedCodec(String name) {
- for (AudioCodec codec : getSystemSupportedCodecs()) {
- if (codec.name.equals(name)) return codec;
- }
- return null;
- }
-
- public final String name;
- public final int sampleRate;
- public final int sampleCount;
- public final int defaultType;
-
- private AudioCodec(String name, int sampleRate, int sampleCount, int defaultType) {
- this.name = name;
- this.sampleRate = sampleRate;
- this.sampleCount = sampleCount;
- this.defaultType = defaultType;
- }
-}
diff --git a/src/android/net/rtp/AudioGroup.java b/src/android/net/rtp/AudioGroup.java
deleted file mode 100644
index 0708613..0000000
--- a/src/android/net/rtp/AudioGroup.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.rtp;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- */
-public class AudioGroup {
- public static final int MODE_ON_HOLD = 0;
- public static final int MODE_MUTED = 1;
- public static final int MODE_NORMAL = 2;
- public static final int MODE_EC_ENABLED = 3;
-
- private final Map<AudioStream, Integer> mStreams;
- private int mMode = MODE_ON_HOLD;
-
- private int mNative;
- static {
- System.loadLibrary("rtp_jni");
- }
-
- public AudioGroup() {
- mStreams = new HashMap<AudioStream, Integer>();
- }
-
- public int getMode() {
- return mMode;
- }
-
- public synchronized native void setMode(int mode);
-
- synchronized void add(AudioStream stream, AudioCodec codec, int codecType, int dtmfType) {
- if (!mStreams.containsKey(stream)) {
- try {
- int id = add(stream.getMode(), stream.dup(),
- stream.getRemoteAddress().getHostAddress(), stream.getRemotePort(),
- codec.name, codec.sampleRate, codec.sampleCount, codecType, dtmfType);
- mStreams.put(stream, id);
- } catch (NullPointerException e) {
- throw new IllegalStateException(e);
- }
- }
- }
-
- private native int add(int mode, int socket, String remoteAddress, int remotePort,
- String codecName, int sampleRate, int sampleCount, int codecType, int dtmfType);
-
- synchronized void remove(AudioStream stream) {
- Integer id = mStreams.remove(stream);
- if (id != null) {
- remove(id);
- }
- }
-
- private native void remove(int id);
-
- /**
- * Sends a DTMF digit to every {@link AudioStream} in this group. Currently
- * only event {@code 0} to {@code 15} are supported.
- *
- * @throws IllegalArgumentException if the event is invalid.
- */
- public native synchronized void sendDtmf(int event);
-
- public synchronized void reset() {
- remove(-1);
- }
-
- @Override
- protected void finalize() throws Throwable {
- reset();
- super.finalize();
- }
-}
diff --git a/src/android/net/rtp/AudioStream.java b/src/android/net/rtp/AudioStream.java
deleted file mode 100644
index c1da7ba..0000000
--- a/src/android/net/rtp/AudioStream.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.rtp;
-
-import java.net.InetAddress;
-import java.net.SocketException;
-
-/**
- * AudioStream represents a RTP stream carrying audio payloads.
- */
-public class AudioStream extends RtpStream {
- private AudioCodec mCodec;
- private int mCodecType = -1;
- private int mDtmfType = -1;
- private AudioGroup mGroup;
-
- /**
- * Creates an AudioStream on the given local address. Note that the local
- * port is assigned automatically to conform with RFC 3550.
- *
- * @param address The network address of the local host to bind to.
- * @throws SocketException if the address cannot be bound or a problem
- * occurs during binding.
- */
- public AudioStream(InetAddress address) throws SocketException {
- super(address);
- }
-
- /**
- * Returns {@code true} if the stream already joined an {@link AudioGroup}.
- */
- @Override
- public final boolean isBusy() {
- return mGroup != null;
- }
-
- /**
- * Returns the joined {@link AudioGroup}.
- */
- public AudioGroup getAudioGroup() {
- return mGroup;
- }
-
- /**
- * Joins an {@link AudioGroup}. Each stream can join only one group at a
- * time. The group can be changed by passing a different one or removed
- * by calling this method with {@code null}.
- *
- * @param group The AudioGroup to join or {@code null} to leave.
- * @throws IllegalStateException if the stream is not properly configured.
- * @see AudioGroup
- */
- public void join(AudioGroup group) {
- if (mGroup == group) {
- return;
- }
- if (mGroup != null) {
- mGroup.remove(this);
- mGroup = null;
- }
- if (group != null) {
- group.add(this, mCodec, mCodecType, mDtmfType);
- mGroup = group;
- }
- }
-
- /**
- * Sets the {@link AudioCodec} and its RTP payload type. According to RFC
- * 3551, the type must be in the range of 0 and 127, where 96 and above are
- * dynamic types. For codecs with static mappings (non-negative
- * {@link AudioCodec#defaultType}), assigning a different non-dynamic type
- * is disallowed.
- *
- * @param codec The AudioCodec to be used.
- * @param type The RTP payload type.
- * @throws IllegalArgumentException if the type is invalid or used by DTMF.
- * @throws IllegalStateException if the stream is busy.
- */
- public void setCodec(AudioCodec codec, int type) {
- if (isBusy()) {
- throw new IllegalStateException("Busy");
- }
- if (type < 0 || type > 127 || (type != codec.defaultType && type < 96)) {
- throw new IllegalArgumentException("Invalid type");
- }
- if (type == mDtmfType) {
- throw new IllegalArgumentException("The type is used by DTMF");
- }
- mCodec = codec;
- mCodecType = type;
- }
-
- /**
- * Sets the RTP payload type for dual-tone multi-frequency (DTMF) digits.
- * The primary usage is to send digits to the remote gateway to perform
- * certain tasks, such as second-stage dialing. According to RFC 2833, the
- * RTP payload type for DTMF is assigned dynamically, so it must be in the
- * range of 96 and 127. One can use {@code -1} to disable DTMF and free up
- * the previous assigned value. This method cannot be called when the stream
- * already joined an {@link AudioGroup}.
- *
- * @param type The RTP payload type to be used or {@code -1} to disable it.
- * @throws IllegalArgumentException if the type is invalid or used by codec.
- * @throws IllegalStateException if the stream is busy.
- * @see AudioGroup#sendDtmf(int)
- */
- public void setDtmfType(int type) {
- if (isBusy()) {
- throw new IllegalStateException("Busy");
- }
- if (type != -1) {
- if (type < 96 || type > 127) {
- throw new IllegalArgumentException("Invalid type");
- }
- if (type == mCodecType) {
- throw new IllegalArgumentException("The type is used by codec");
- }
- }
- mDtmfType = type;
- }
-}
diff --git a/src/android/net/rtp/RtpStream.java b/src/android/net/rtp/RtpStream.java
deleted file mode 100644
index b542ca7..0000000
--- a/src/android/net/rtp/RtpStream.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.rtp;
-
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.SocketException;
-
-/**
- * RtpStream represents a base class of media streams running over
- * Real-time Transport Protocol (RTP).
- */
-public class RtpStream {
- public static final int MODE_NORMAL = 0;
- public static final int MODE_SEND_ONLY = 1;
- public static final int MODE_RECEIVE_ONLY = 2;
-
- private final InetAddress mLocalAddress;
- private final int mLocalPort;
-
- private InetAddress mRemoteAddress;
- private int mRemotePort = -1;
- private int mMode = MODE_NORMAL;
-
- private int mNative;
- static {
- System.loadLibrary("rtp_jni");
- }
-
- /**
- * Creates a RtpStream on the given local address. Note that the local
- * port is assigned automatically to conform with RFC 3550.
- *
- * @param address The network address of the local host to bind to.
- * @throws SocketException if the address cannot be bound or a problem
- * occurs during binding.
- */
- RtpStream(InetAddress address) throws SocketException {
- mLocalPort = create(address.getHostAddress());
- mLocalAddress = address;
- }
-
- private native int create(String address) throws SocketException;
-
- /**
- * Returns the network address of the local host.
- */
- public InetAddress getLocalAddress() {
- return mLocalAddress;
- }
-
- /**
- * Returns the network port of the local host.
- */
- public int getLocalPort() {
- return mLocalPort;
- }
-
- /**
- * Returns the network address of the remote host or {@code null} if the
- * stream is not associated.
- */
- public InetAddress getRemoteAddress() {
- return mRemoteAddress;
- }
-
- /**
- * Returns the network port of the remote host or {@code -1} if the stream
- * is not associated.
- */
- public int getRemotePort() {
- return mRemotePort;
- }
-
- /**
- * Returns {@code true} if the stream is busy. This method is intended to be
- * overridden by subclasses.
- */
- public boolean isBusy() {
- return false;
- }
-
- /**
- * Returns the current mode. The initial mode is {@link #MODE_NORMAL}.
- */
- public int getMode() {
- return mMode;
- }
-
- /**
- * Changes the current mode. It must be one of {@link #MODE_NORMAL},
- * {@link #MODE_SEND_ONLY}, and {@link #MODE_RECEIVE_ONLY}.
- *
- * @param mode The mode to change to.
- * @throws IllegalArgumentException if the mode is invalid.
- * @throws IllegalStateException if the stream is busy.
- * @see #isBusy()
- */
- public void setMode(int mode) {
- if (isBusy()) {
- throw new IllegalStateException("Busy");
- }
- if (mode != MODE_NORMAL && mode != MODE_SEND_ONLY && mode != MODE_RECEIVE_ONLY) {
- throw new IllegalArgumentException("Invalid mode");
- }
- mMode = mode;
- }
-
- /**
- * Associates with a remote host.
- *
- * @param address The network address of the remote host.
- * @param port The network port of the remote host.
- * @throws IllegalArgumentException if the address is not supported or the
- * port is invalid.
- * @throws IllegalStateException if the stream is busy.
- * @see #isBusy()
- */
- public void associate(InetAddress address, int port) {
- if (isBusy()) {
- throw new IllegalStateException("Busy");
- }
- if (!(address instanceof Inet4Address && mLocalAddress instanceof Inet4Address) &&
- !(address instanceof Inet6Address && mLocalAddress instanceof Inet6Address)) {
- throw new IllegalArgumentException("Unsupported address");
- }
- if (port < 0 || port > 65535) {
- throw new IllegalArgumentException("Invalid port");
- }
- mRemoteAddress = address;
- mRemotePort = port;
- }
-
- synchronized native int dup();
-
- /**
- * Releases allocated resources. The stream becomes inoperable after calling
- * this method.
- *
- * @throws IllegalStateException if the stream is busy.
- * @see #isBusy()
- */
- public void release() {
- if (isBusy()) {
- throw new IllegalStateException("Busy");
- }
- close();
- }
-
- private synchronized native void close();
-
- @Override
- protected void finalize() throws Throwable {
- close();
- super.finalize();
- }
-}
diff --git a/src/com/android/sip/rtp/AudioCodec.java b/src/com/android/sip/rtp/AudioCodec.java
deleted file mode 100644
index 1e298b2..0000000
--- a/src/com/android/sip/rtp/AudioCodec.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip.rtp;
-
-public class AudioCodec {
- public static final AudioCodec ULAW = new AudioCodec("PCMU", 8000, 160, 0);
- public static final AudioCodec ALAW = new AudioCodec("PCMA", 8000, 160, 8);
-
- /**
- * Returns system supported codecs.
- */
- public static AudioCodec[] getSystemSupportedCodecs() {
- return new AudioCodec[] {AudioCodec.ULAW, AudioCodec.ALAW};
- }
-
- /**
- * Returns the codec instance if it is supported by the system.
- *
- * @param name name of the codec
- * @return the matched codec or null if the codec name is not supported by
- * the system
- */
- public static AudioCodec getSystemSupportedCodec(String name) {
- for (AudioCodec codec : getSystemSupportedCodecs()) {
- if (codec.name.equals(name)) return codec;
- }
- return null;
- }
-
- public final String name;
- public final int sampleRate;
- public final int sampleCount;
- public final int defaultType;
-
- private AudioCodec(String name, int sampleRate, int sampleCount, int defaultType) {
- this.name = name;
- this.sampleRate = sampleRate;
- this.sampleCount = sampleCount;
- this.defaultType = defaultType;
- }
-}
diff --git a/src/com/android/sip/rtp/AudioStream.java b/src/com/android/sip/rtp/AudioStream.java
deleted file mode 100644
index e4a98aa..0000000
--- a/src/com/android/sip/rtp/AudioStream.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip.rtp;
-
-
-/**
- * The AudioStream class represents a RTP stream carrying audio payloads.
- */
-public class AudioStream {
- private int mNative;
- private final RtpSocket mRtpSocket;
-
- private AudioCodec mCodec;
- private int mCodecType = -1;
- private int mDtmfType = -1;
-
- static {
- System.loadLibrary("siprtp");
- }
-
- /**
- * Creates an AudioStream on a given {@link RtpSocket}.
- *
- * @param rtpSocket The socket to send and receive RTP packets.
- * @throws IllegalStateException if the socket is not associated or is
- * already used by another stream.
- */
- public AudioStream(RtpSocket rtpSocket) {
- rtpSocket.occupy();
- mRtpSocket = rtpSocket;
- }
-
- /**
- * Closes the stream. Once closed, the stream stops sending and receiving,
- * and relinquishes the ownership of the {@link RtpSocket}.
- */
- public void close() {
- stopSending();
- stopReceiving();
- mRtpSocket.vacate();
- }
-
- /**
- * Returns the bound {@link RtpSocket}.
- */
- public RtpSocket getRtpSocket() {
- return mRtpSocket;
- }
-
- /**
- * Sets the {@link AudioCodec} and the RTP payload type. According to RFC
- * 3551, the type must be in the range of 0 and 127, where 96 and above are
- * used by dynamic types. For codecs with static mappings (non-negative
- * {@link AudioCodec#defaultType}), assigning a different non-dynamic type
- * is disallowed. This method can be called at any time but only takes
- * effect after the next call to {@link #prepare()}.
- *
- * @param codec The audio codec to be used.
- * @param type The RTP payload type.
- * @throws IllegalArgumentException if the type is out of range or
- * disallowed for this codec.
- * @throws IllegalStateException if the type is already used by DTMF.
- */
- public synchronized void setCodec(AudioCodec codec, int type) {
- if (type < 0 || type > 127) {
- throw new IllegalArgumentException("The type is out of range");
- }
- if (type != codec.defaultType && type < 96) {
- throw new IllegalArgumentException(
- "Assigning a different non-dynamic type is not allowed");
- }
- if (type == mDtmfType) {
- throw new IllegalStateException("Codec and DTMF cannot use the same type");
- }
- mCodec = codec;
- mCodecType = type;
- }
-
- /**
- * Sets the RTP payload type for dual-tone multi-frequency (DTMF) digits.
- * The primary usage is to send digits to the remote gateway to perform
- * certain tasks, such as second-stage dialing. According to RFC 2833, the
- * RTP payload type for DTMF is assigned dynamically, so it must be in the
- * range of 96 and 127. One can use {@code -1} to disable DTMF and free up
- * the previous assigned mapping. This method can be called at any time but
- * only takes effect after the next call to {@link #prepare()}.
- *
- * @param type The RTP payload type or {@code -1} to disable DTMF.
- * @throws IllegalArgumentException if the type is out of range.
- * @throws IllegalStateException if the type is already used by the codec.
- * @see #sendDtmf(int)
- */
- public synchronized void setDtmf(int type) {
- if (type != -1) {
- if (type < 96 || type > 127) {
- throw new IllegalArgumentException("The type is out of range");
- }
- if (type == mCodecType) {
- throw new IllegalStateException("Codec and DTMF cannot use the same type");
- }
- }
- mDtmfType = type;
- }
-
- /**
- * Allocates native resources for the current configuration.
- *
- * @throws IllegalStateException if the codec is not set or the stream is
- * already prepared.
- */
- public synchronized void prepare() {
- if (mCodec == null) {
- throw new IllegalStateException("Codec is not set");
- }
- prepare(mRtpSocket, mCodec.name, mCodec.sampleRate,
- mCodec.sampleCount, mCodecType, mDtmfType);
- }
- private native void prepare(RtpSocket rtpSocket, String codecName,
- int sampleRate, int sampleCount, int codecType, int dtmfType);
-
- /**
- * Returns {@code true} if the stream is already prepared.
- */
- public native synchronized boolean isPrepared();
-
- /**
- * Starts recording and sending encoded audio to the remote host.
- *
- * @throws IllegalStateException if the stream is not prepared.
- */
- public native synchronized void startSending();
-
- /**
- * Starts receiving and playing decoded audio from the remote host.
- *
- * @throws IllegalStateException if the stream is not prepared.
- */
- public native synchronized void startReceiving();
-
- /**
- * Sends a DTMF digit to the remote host. One must set the RTP payload type
- * for DTMF before calling this method. Currently only events {@code 0}
- * through {@code 15} are supported.
- *
- * @throws IllegalArgumentException if the event is out of range.
- * @throws IllegalStateException if the stream is not sending or DTMF is
- * disabled.
- * @see #setDtmf(int)
- */
- public native synchronized void sendDtmf(int event);
-
- /**
- * Stops sending.
- */
- public native synchronized void stopSending();
-
- /**
- * Stops receiving.
- */
- public native synchronized void stopReceiving();
-
- /**
- * Releases native resources. It also stops sending and receiving. After
- * calling this method, one can call {@link #prepare()} again with or
- * without changing the configuration.
- */
- public native synchronized void release();
-
- @Override
- protected void finalize() throws Throwable {
- release();
- super.finalize();
- }
-}
diff --git a/src/com/android/sip/rtp/RtpSocket.java b/src/com/android/sip/rtp/RtpSocket.java
deleted file mode 100644
index 1f29f21..0000000
--- a/src/com/android/sip/rtp/RtpSocket.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip.rtp;
-
-import java.net.InetAddress;
-import java.net.SocketException;
-
-/**
- * The RtpSocket class represents a UDP socket carrying RTP packets. The network
- * port of the local host is assigned automatically to conform with RFC 3550.
- */
-public class RtpSocket {
- private int mNative;
- private final InetAddress mLocalAddress;
- private final int mLocalPort;
-
- private InetAddress mRemoteAddress;
- private int mRemotePort = -1;
- private boolean mInUse = false;
-
- static {
- System.loadLibrary("siprtp");
- }
-
- /**
- * Creates a RtpSocket by specifying the network address of the local host.
- *
- * @param address The network address of the local host to bind to.
- * @throws SocketException if the address cannot be bound or a problem
- * occurs during binding.
- */
- public RtpSocket(InetAddress address) throws SocketException {
- mLocalPort = create(address.getHostAddress());
- mLocalAddress = address;
- }
- private native int create(String address) throws SocketException;
-
- synchronized void occupy() {
- if (mRemoteAddress == null) {
- throw new IllegalStateException("RtpSocket is not associated");
- }
- if (mInUse) {
- throw new IllegalStateException("RtpSocket is already in use");
- }
- mInUse = true;
- }
-
- synchronized void vacate() {
- mInUse = false;
- }
-
- /**
- * Returns the network address of the local host.
- */
- public InetAddress getLocalAddress() {
- return mLocalAddress;
- }
-
- /**
- * Returns the network port of the local host.
- */
- public int getLocalPort() {
- return mLocalPort;
- }
-
- /**
- * Returns the network address of the remote host or {@code null} if the
- * socket is not associated.
- */
- public InetAddress getRemoteAddress() {
- return mRemoteAddress;
- }
-
- /**
- * Returns the network port of the remote host or {@code -1} if the socket
- * is not associated.
- */
- public int getRemotePort() {
- return mRemotePort;
- }
-
- /**
- * Associates with a remote host.
- *
- * @param address The network address of the remote host.
- * @param port The network port of the remote host.
- * @throws SocketException if the address family is different or the socket
- * is already associated.
- */
- public synchronized void associate(InetAddress address, int port)
- throws SocketException {
- associate(address.getHostAddress(), port);
- mRemoteAddress = address;
- mRemotePort = port;
- }
- private native void associate(String address, int port) throws SocketException;
-
- @Override
- protected void finalize() throws Throwable {
- release();
- super.finalize();
- }
- private native void release();
-}
diff --git a/src/jni/rtp/Android.mk b/src/jni/rtp/Android.mk
deleted file mode 100644
index fb1fdb8..0000000
--- a/src/jni/rtp/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libsiprtp
-
-LOCAL_SRC_FILES := \
- RtpSocket.cpp \
- AudioStream.cpp \
- G711Codec.cpp \
- libsiprtp.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libnativehelper \
- libutils \
- libcutils \
- libmedia
-
-LOCAL_STATIC_LIBRARIES :=
-
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
-
-LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_PRELINK_MODULE := false
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/src/jni/rtp/AudioCodec.h b/src/jni/rtp/AudioCodec.h
deleted file mode 100644
index f9aee94..0000000
--- a/src/jni/rtp/AudioCodec.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyrightm (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __AUDIO_CODEC_H__
-#define __AUDIO_CODEC_H__
-
-class AudioCodec
-{
-public:
- virtual ~AudioCodec() {}
- // Returns true if sampleCount is acceptable.
- virtual bool set(int sampleCount) = 0;
- // Returns the length of payload in bytes.
- virtual int encode(void *payload, int16_t *samples) = 0;
- // Returns the number of decoded samples.
- virtual int decode(int16_t *samples, void *payload, int length) = 0;
-};
-
-class UlawCodec : public AudioCodec
-{
-public:
- virtual bool set(int sampleCount) {
- mSampleCount = sampleCount;
- return true;
- }
- virtual int encode(void *payload, int16_t *samples);
- virtual int decode(int16_t *samples, void *payload, int length);
-private:
- int mSampleCount;
-};
-
-class AlawCodec : public AudioCodec
-{
-public:
- virtual bool set(int sampleCount) {
- mSampleCount = sampleCount;
- return true;
- }
- virtual int encode(void *payload, int16_t *samples);
- virtual int decode(int16_t *samples, void *payload, int length);
-private:
- int mSampleCount;
-};
-
-#endif
diff --git a/src/jni/rtp/AudioStream.cpp b/src/jni/rtp/AudioStream.cpp
deleted file mode 100644
index 8093414..0000000
--- a/src/jni/rtp/AudioStream.cpp
+++ /dev/null
@@ -1,660 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <time.h>
-#include <arpa/inet.h>
-#include <pthread.h>
-
-#define LOG_TAG "AudioStream"
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-#include <media/AudioRecord.h>
-#include <media/AudioTrack.h>
-#include <media/mediarecorder.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-
-#include "RtpSocket.h"
-#include "AudioCodec.h"
-
-using namespace android;
-
-static int gRandom = -1;
-
-class JitterBuffer {
- static const int SIZE = 6;
- uint32_t mBufferSize;
- uint8_t *mBuffer[SIZE];
- uint16_t *mLength;
- uint16_t mHead;
- uint16_t mTail;
-
- public:
- JitterBuffer(int sampleCount) {
- mHead = mTail = 0;
- mBufferSize = 2048 + (sizeof(int16_t) * sampleCount);
- for (int i = 0; i < SIZE ; ++i) {
- mBuffer[i] = (uint8_t*) malloc(mBufferSize);
- }
- mLength = (uint16_t*) malloc(SIZE * sizeof(uint16_t));
- }
-
- ~JitterBuffer() {
- for (int i = 0; i < SIZE ; ++i) {
- free(mBuffer[i]);
- }
- free(mLength);
- }
-
- int getBufferSize() {
- return mBufferSize;
- }
-
- uint8_t* obtainBuffer() {
- // we need extra buffer to save one memcpy.
- int reservedHead = ((mHead == 0) ? (SIZE - 1) : (mHead - 1));
- if (mTail == reservedHead) return NULL;
- return mBuffer[mTail];
- }
-
- void pushBack(int length) {
- mLength[mTail] = length;
- if (++mTail == SIZE) mTail = 0;
- }
-
- unsigned int popFront(uint8_t **packet) {
- int length = mLength[mHead];
- *packet = mBuffer[mHead];
- if (++mHead == SIZE) mHead = 0;
- return length;
- }
-
- bool empty() {
- return (mHead == mTail);
- }
-};
-
-class AudioStream
-{
-public:
- AudioStream();
- ~AudioStream();
-
- bool set(RtpSocket *rtpSocket, const char *codecName,
- int sampleRate, int sampleCount, int codecType, int dtmfType);
-
- bool startSending();
- bool startReceiving();
- bool sendDtmf(int event);
- void stopSending();
- void stopReceiving();
-
-private:
- RtpSocket *mSocket;
- AudioCodec *mCodec;
- AudioRecord mRecord;
- AudioTrack mTrack;
- pthread_mutex_t mDtmfLock;
-
- uint16_t mLocalSequence;
- uint32_t mLocalTimestamp;
- uint32_t mLocalSsrc;
- uint32_t mRemoteTimestamp;
- uint32_t mRemoteSsrc;
- uint32_t mCodecMagic;
- uint32_t mDtmfMagic;
-
- int mSampleRate;
- int mSampleCount;
- int mInterval;
- int mTimer;
-
- JitterBuffer *mJitterBuffer;
-
- volatile int32_t mNextDtmfEvent;
- int mDtmfEvent;
- int mDtmfDuration;
-
- bool encode();
- bool decode();
-
- void adjustMicGain(int16_t *buf, int len, int factor);
-
- int getPacketFromJB(RtpSocket *rtpSocket, uint8_t **buffer, timeval *deadline);
-
- class Sender : public Thread
- {
- public:
- Sender(AudioStream *stream) : Thread(false), mStream(stream) {}
- private:
- virtual bool threadLoop()
- {
- if (!mStream->encode()) {
- mStream->mRecord.stop();
- return false;
- }
- return true;
- }
- AudioStream *mStream;
- };
- sp<Sender> mSender;
-
- class Receiver : public Thread
- {
- public:
- Receiver(AudioStream *stream) : Thread(false), mStream(stream) {}
- private:
- virtual bool threadLoop()
- {
- if (!mStream->decode()) {
- mStream->mTrack.stop();
- return false;
- }
- return true;
- }
- AudioStream *mStream;
- };
- sp<Receiver> mReceiver;
-};
-
-AudioStream::AudioStream()
-{
- mSender = new Sender(this);
- mReceiver = new Receiver(this);
- mCodec = NULL;
- mJitterBuffer = NULL;
- pthread_mutex_init(&mDtmfLock, NULL);
-}
-
-AudioStream::~AudioStream()
-{
- stopSending();
- stopReceiving();
- mSender.clear();
- mReceiver.clear();
- delete mCodec;
- delete mJitterBuffer;
-}
-
-bool AudioStream::set(RtpSocket *rtpSocket, const char *codecName,
- int sampleRate, int sampleCount, int codecType, int dtmfType)
-{
- mSocket = rtpSocket;
-
- // One frame per second is just not reasonable.
- if (sampleRate <= 0 || sampleCount <= 0 || sampleRate <= sampleCount) {
- return false;
- }
-
- // Find AudioCodec and configure it.
- if (strcmp("PCMU", codecName) == 0) {
- mCodec = new UlawCodec;
- } else if (strcmp("PCMA", codecName) == 0) {
- mCodec = new AlawCodec;
- } else {
- mCodec = NULL;
- }
- if (mCodec == NULL || !mCodec->set(sampleCount)) {
- return false;
- }
-
- // Set AudioRecord with double buffer. Otherwise try system default.
- if (mRecord.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
- AudioSystem::CHANNEL_IN_MONO, sampleCount * 2) != NO_ERROR &&
- mRecord.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
- AudioSystem::CHANNEL_IN_MONO) != NO_ERROR) {
- return false;
- }
-
- // Set AudioTrack with double buffer. Otherwise try system default.
- if (mTrack.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
- AudioSystem::CHANNEL_OUT_MONO, sampleCount * 2) != NO_ERROR &&
- mTrack.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
- AudioSystem::CHANNEL_OUT_MONO) != NO_ERROR) {
- return false;
- }
-
- // Only initialize these random bits once for the maximum compatibility.
- read(gRandom, &mLocalSequence, sizeof(mLocalSequence));
- read(gRandom, &mLocalTimestamp, sizeof(mLocalTimestamp));
- read(gRandom, &mLocalSsrc, sizeof(mLocalSsrc));
-
- mCodecMagic = (0x8000 | codecType) << 16;
- mDtmfMagic = (dtmfType == -1 ? -1 : (0x8000 | dtmfType) << 16);
-
- mSampleRate = sampleRate;
- mSampleCount = sampleCount;
-
- if (mJitterBuffer == NULL) {
- mJitterBuffer = new JitterBuffer(sampleCount);
- }
-
- // mInterval is a threshold for jitter control in microseconds. To avoid
- // introducing more latencies, here we use 0.8 times of the real interval.
- mInterval = 1000 * sampleCount / sampleRate * 800;
-
- return true;
-}
-
-bool AudioStream::startSending()
-{
- if (mRecord.stopped()) {
- mTimer = 0;
- mNextDtmfEvent = -1;
- mDtmfEvent = -1;
-
- if (mRecord.start() != NO_ERROR ||
- mSender->run("Sender", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
- mRecord.stop();
- return false;
- }
- }
- return true;
-}
-
-bool AudioStream::startReceiving()
-{
- if (mTrack.stopped()) {
- mRemoteTimestamp = 0;
- mRemoteSsrc = 0;
-
- mTrack.start();
- if (mReceiver->run("Receiver", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
- mTrack.stop();
- return false;
- }
- }
- return true;
-}
-
-bool AudioStream::sendDtmf(int event)
-{
- if (mRecord.stopped() || ~mDtmfMagic == 0) {
- return false;
- }
- if (pthread_mutex_trylock(&mDtmfLock) != 0) {
- usleep(mInterval * 2);
- if (pthread_mutex_trylock(&mDtmfLock) != 0) return false;
- }
- mNextDtmfEvent = event;
- pthread_mutex_unlock(&mDtmfLock);
- return true;
-}
-
-void AudioStream::stopSending()
-{
- if (!mRecord.stopped()) {
- mSender->requestExitAndWait();
- mRecord.stop();
- }
-}
-
-void AudioStream::stopReceiving()
-{
- if (!mTrack.stopped()) {
- mReceiver->requestExitAndWait();
- mTrack.stop();
- }
-}
-
-// TODO: remove this function after the mic level issue was fixed in driver.
-void AudioStream::adjustMicGain(int16_t *buf, int len, int factor)
-{
- int i, j;
- int bound = 32768/factor;
- for (i = 0; i < len; i++) {
- j = buf[i];
- if (j > bound) {
- buf[i] = 32767;
- } else if (j < -bound) {
- buf[i] = -32767;
- } else {
- buf[i] = (int16_t)(factor*j);
- }
- }
-}
-
-// -----------------------------------------------------------------------------
-
-bool AudioStream::encode()
-{
- int16_t samples[mSampleCount];
-
- // Read samples from AudioRecord. Since AudioRecord itself has fault
- // recovery mechanism, we just return false if the length is wrong.
- int length = mRecord.read(samples, sizeof(samples));
- if (length - sizeof(samples) != 0) {
- LOGD("read");
- return false;
- }
-
- adjustMicGain(samples, length/sizeof(int16_t), 8);
-
- mLocalSequence++;
- mLocalTimestamp += mSampleCount;
-
- // If we have a DTMF event to send, send it now.
- pthread_mutex_lock(&mDtmfLock);
- int32_t event = mNextDtmfEvent;
- mNextDtmfEvent = -1;
- pthread_mutex_unlock(&mDtmfLock);
- if (event != -1) {
- mDtmfEvent = event << 24;
- mDtmfDuration = 0;
- }
- if (mDtmfEvent != -1) {
- mDtmfDuration += mSampleCount;
- uint32_t packet[4] = {
- htonl(mDtmfMagic | mLocalSequence),
- htonl(mLocalTimestamp - mDtmfDuration),
- mLocalSsrc,
- htonl(mDtmfEvent | mDtmfDuration),
- };
- // Make the DTMF event roughly 200 millisecond long.
- if (mDtmfDuration * 5 >= mSampleRate) {
- packet[3] |= 1 << 24;
- mDtmfEvent = -1;
- }
- send(mSocket, packet, sizeof(packet));
- return true;
- }
-
- // Otherwise encode the samples and prepare the packet.
- __attribute__((aligned(4))) uint8_t packet[12 + sizeof(samples)];
-
- uint32_t *header = (uint32_t *)packet;
- header[0] = htonl(mCodecMagic | mLocalSequence);
- header[1] = htonl(mLocalTimestamp);
- header[2] = mLocalSsrc;
-
- length = mCodec->encode(&packet[12], samples);
- if (length <= 0) {
- LOGD("encode");
- return false;
- }
- length += 12;
-
- // Here we implement a simple jitter control for the outgoing packets.
- // Ideally we should send out packets at a constant rate, but in practice
- // every component in the pipeline might delay or speed up a little. To
- // avoid making things worse, we only delay the packet which comes early.
- // Note that interval is less than the real one, so the delay will be
- // converged.
- timeval now;
- if (gettimeofday(&now, NULL) != 0) {
- LOGD("gettimeofday");
- return false;
- }
- int interval = now.tv_sec * 1000000 + now.tv_usec - mTimer;
- if (interval > 0 && interval < mInterval) {
- usleep(mInterval - interval);
- interval = mInterval;
- }
- mTimer += interval;
-
- send(mSocket, packet, length);
- return true;
-}
-
-bool AudioStream::decode()
-{
- timeval deadline;
-
- if (gettimeofday(&deadline, NULL) != 0) {
- LOGD("gettimeofday");
- return false;
- }
-
- // mInterval is always less than 1000000.
- deadline.tv_usec += mInterval;
- if (deadline.tv_usec > 1000000) {
- deadline.tv_usec -= 1000000;
- deadline.tv_sec++;
- }
-
- int16_t samples[mSampleCount];
- uint8_t *packet;
-
- while (1) {
- int length = getPacketFromJB(mSocket, &packet, &deadline);
- if (length <= 0) {
- return true;
- }
- if (length < 12) {
- continue;
- }
-
- // Here we check all the fields in the standard RTP header. Some
- // restrictions might be too tight and could be removed in the future.
- int offset = 12 + (packet[0] & 0x0F) * 4;
- if ((packet[0] & 0x10) != 0) {
- offset += 4 + (packet[offset + 2] << 8 | packet[offset + 3]) * 4;
- }
- if ((packet[0] & 0x20) != 0 && length - sizeof(packet) <= 0) {
- length -= packet[length - 1];
- }
- length -= offset;
- if (length < 0) {
- continue;
- }
-
- uint32_t *header = (uint32_t *)packet;
- header[0] = ntohl(header[0]);
- header[1] = ntohl(header[1]);
-
- if ((header[0] & 0xC07F0000) != mCodecMagic) {
- LOGD("wrong magic (%X != %X)", mCodecMagic, header[0] & 0xC07F0000);
- continue;
- }
-
- mRemoteTimestamp = header[1];
- mRemoteSsrc = header[2];
-
- length = mCodec->decode(samples, &packet[offset], length) * 2;
- if (length <= 0) {
- LOGD("decode");
- continue;
- }
-
- // Write samples to AudioTrack. Again, since AudioTrack itself has fault
- // recovery mechanism, we just return false if the length is wrong.
- return mTrack.write(samples, length) == length;
- }
-}
-
-int AudioStream::getPacketFromJB(RtpSocket *rtpSocket, uint8_t **buffer,
- timeval *deadline)
-{
- // Here we implement a simple jitter control for the incoming packets.
- // Ideally there should be only one packet every time we try to read
- // from the socket. If any packets are late, we must drop incoming packets
- // if the jitter buffer is full already.
-
- int result, count = 0;
- if (mJitterBuffer->empty()) {
- *buffer = mJitterBuffer->obtainBuffer();
- result = receive(rtpSocket, *buffer, mJitterBuffer->getBufferSize(),
- deadline);
- if (result <= 0) return result;
- mJitterBuffer->pushBack(result);
- }
- result = mJitterBuffer->popFront(buffer);
- while (1) {
- void *fillBuffer = (void*) mJitterBuffer->obtainBuffer();
- int length = receive(mSocket, fillBuffer, ((fillBuffer == NULL) ?
- 0 : mJitterBuffer->getBufferSize()), NULL);
- if (length <= 0) break;
- if (fillBuffer != NULL) {
- mJitterBuffer->pushBack(length);
- } else {
- count++;
- }
- }
- if (count > 0) {
- LOGD("Drop %d packet(s), jitter buffer is full!", count);
- }
- return result;
-}
-// -----------------------------------------------------------------------------
-
-static jfieldID gNative;
-
-static void throwIllegalStateException(JNIEnv *env, const char *message)
-{
- jniThrowException(env, "java/lang/IllegalStateException", message);
-}
-
-// All these JNI methods are synchronized in java class, so we implement them
-// without using any mutex locks. Simple is best!
-
-static void prepare(JNIEnv *env, jobject thiz, jobject jRtpSocket,
- jstring jCodecName, jint sampleRate, jint sampleCount, jint codecType,
- jint dtmfType)
-{
- AudioStream *stream = (AudioStream *)env->GetIntField(thiz, gNative);
- if (stream != NULL) {
- throwIllegalStateException(env, "Already prepared");
- return;
- }
-
- RtpSocket *rtpSocket = getRtpSocket(env, jRtpSocket, true);
- if (rtpSocket == NULL) {
- // Exception already thrown.
- return;
- }
-
- if (jCodecName == NULL) {
- jniThrowNullPointerException(env, "codecName");
- return;
- }
-
- const char *codecName = env->GetStringUTFChars(jCodecName, NULL);
- stream = new AudioStream;
- if (!stream->set(rtpSocket, codecName, sampleRate, sampleCount, codecType,
- dtmfType)) {
- delete stream;
- stream = NULL;
- }
- env->ReleaseStringUTFChars(jCodecName, codecName);
-
- if (stream == NULL) {
- throwIllegalStateException(env, "Failed to create native AudioStream");
- }
- env->SetIntField(thiz, gNative, (int)stream);
-}
-
-static jboolean isPrepared(JNIEnv *env, jobject thiz)
-{
- return env->GetIntField(thiz, gNative) != 0;
-}
-
-static void startSending(JNIEnv *env, jobject thiz)
-{
- AudioStream *stream = (AudioStream *)env->GetIntField(thiz, gNative);
- if (stream == NULL) {
- throwIllegalStateException(env, "Not prepared");
- } else if (!stream->startSending()) {
- throwIllegalStateException(env, "Failed to start native AudioRecord");
- }
-}
-
-static void startReceiving(JNIEnv *env, jobject thiz)
-{
- AudioStream *stream = (AudioStream *)env->GetIntField(thiz, gNative);
- if (stream == NULL) {
- throwIllegalStateException(env, "Not prepared");
- } else if (!stream->startReceiving()) {
- throwIllegalStateException(env, "Failed to start native AudioTrack");
- }
-}
-
-static void sendDtmf(JNIEnv *env, jobject thiz, jint event)
-{
- AudioStream *stream = (AudioStream *)env->GetIntField(thiz, gNative);
- if (stream == NULL) {
- throwIllegalStateException(env, "Not prepared");
- } else if (event < 0 || event > 15) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "event");
- } else if (!stream->sendDtmf(event)) {
- throwIllegalStateException(env, "Failed to send DTMF");
- }
-}
-
-static void stopSending(JNIEnv *env, jobject thiz)
-{
- AudioStream *stream = (AudioStream *)env->GetIntField(thiz, gNative);
- if (stream != NULL) {
- stream->stopSending();
- }
-}
-
-static void stopReceiving(JNIEnv *env, jobject thiz)
-{
- AudioStream *stream = (AudioStream *)env->GetIntField(thiz, gNative);
- if (stream != NULL) {
- stream->stopReceiving();
- }
-}
-
-static void release(JNIEnv *env, jobject thiz)
-{
- delete (AudioStream *)env->GetIntField(thiz, gNative);
- env->SetIntField(thiz, gNative, NULL);
-}
-
-//------------------------------------------------------------------------------
-
-static JNINativeMethod gMethods[] = {
- {"prepare", "(Lcom/android/sip/rtp/RtpSocket;Ljava/lang/String;IIII)V",
- (void *)prepare},
- {"isPrepared", "()Z", (void *)isPrepared},
- {"startSending", "()V", (void *)startSending},
- {"startReceiving", "()V", (void *)startReceiving},
- {"sendDtmf", "(I)V", (void *)sendDtmf},
- {"stopSending", "()V", (void *)stopSending},
- {"stopReceiving", "()V", (void *)stopReceiving},
- {"release", "()V", (void *)release},
-};
-
-int registerAudioStream(JNIEnv *env)
-{
- gRandom = open("/dev/urandom", O_RDONLY);
- if (gRandom == -1) {
- LOGE("urandom: %s", strerror(errno));
- return -1;
- }
-
- jclass clazz;
- if ((clazz = env->FindClass("com/android/sip/rtp/AudioStream")) == NULL ||
- (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
- env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
- LOGE("JNI registration failed");
- return -1;
- }
- return 0;
-}
diff --git a/src/jni/rtp/G711Codec.cpp b/src/jni/rtp/G711Codec.cpp
deleted file mode 100644
index 2226850..0000000
--- a/src/jni/rtp/G711Codec.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyrightm (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include "AudioCodec.h"
-
-static int8_t gExponents[128] = {
- 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-};
-
-int UlawCodec::encode(void *payload, int16_t *samples)
-{
- int8_t *ulaws = (int8_t *)payload;
- for (int i = 0; i < mSampleCount; ++i) {
- int sample = samples[i];
- int sign = (sample >> 8) & 0x80;
- if (sample < 0) {
- sample = -sample;
- }
- sample += 132;
- if (sample > 32767) {
- sample = 32767;
- }
- int exponent = gExponents[sample >> 8];
- int mantissa = (sample >> (exponent + 3)) & 0x0F;
- ulaws[i] = ~(sign | (exponent << 4) | mantissa);
- }
- return mSampleCount;
-}
-
-int UlawCodec::decode(int16_t *samples, void *payload, int length)
-{
- int8_t *ulaws = (int8_t *)payload;
- for (int i = 0; i < length; ++i) {
- int ulaw = ~ulaws[i];
- int exponent = (ulaw >> 4) & 0x07;
- int mantissa = ulaw & 0x0F;
- int sample = (((mantissa << 3) + 132) << exponent) - 132;
- samples[i] = (ulaw < 0 ? -sample : sample);
- }
- return length;
-}
-
-int AlawCodec::encode(void *payload, int16_t *samples)
-{
- int8_t *alaws = (int8_t *)payload;
- for (int i = 0; i < mSampleCount; ++i) {
- int sample = samples[i];
- int sign = (sample >> 8) & 0x80;
- if (sample < 0) {
- sample = -sample;
- }
- if (sample > 32767) {
- sample = 32767;
- }
- int exponent = gExponents[sample >> 8];
- int mantissa = (sample >> (exponent == 0 ? 4 : exponent + 3)) & 0x0F;
- alaws[i] = (sign | (exponent << 4) | mantissa) ^ 0xD5;
- }
- return mSampleCount;
-}
-
-int AlawCodec::decode(int16_t *samples, void *payload, int length)
-{
- int8_t *alaws = (int8_t *)payload;
- for (int i = 0; i < length; ++i) {
- int alaw = alaws[i] ^ 0x55;
- int exponent = (alaw >> 4) & 0x07;
- int mantissa = alaw & 0x0F;
- int sample = (exponent == 0 ? (mantissa << 4) + 8 :
- ((mantissa << 3) + 132) << exponent);
- samples[i] = (alaw < 0 ? sample : -sample);
- }
- return length;
-}
diff --git a/src/jni/rtp/RtpSocket.cpp b/src/jni/rtp/RtpSocket.cpp
deleted file mode 100644
index cc63e3f..0000000
--- a/src/jni/rtp/RtpSocket.cpp
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/time.h>
-#include <time.h>
-
-#define LOG_TAG "RtpSocket"
-#include <utils/Log.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-
-#include "RtpSocket.h"
-
-static jfieldID gNative;
-
-struct RtpSocket
-{
- int mFd;
- int mFamily;
- sockaddr_storage mRemote;
-
- RtpSocket(int fd, sockaddr_storage *local)
- {
- mFd = fd;
- mFamily = local->ss_family;
- mRemote.ss_family = ~mFamily;
- }
-
- ~RtpSocket() { close(mFd); }
-};
-
-//------------------------------------------------------------------------------
-
-RtpSocket *getRtpSocket(JNIEnv *env, jobject jRtpSocket, bool associated)
-{
- if (jRtpSocket == NULL) {
- jniThrowNullPointerException(env, "rtpSocket");
- return NULL;
- }
- RtpSocket *rtpSocket = (RtpSocket *)env->GetIntField(jRtpSocket, gNative);
- if (rtpSocket == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", "native");
- LOGE("native is NULL");
- return NULL;
- }
- if (associated && (rtpSocket->mRemote.ss_family != rtpSocket->mFamily)) {
- jniThrowException(env, "java/lang/IllegalStateException",
- strerror(ENOTCONN));
- return NULL;
- }
- return rtpSocket;
-}
-
-int send(RtpSocket *rtpSocket, void *buffer, int length)
-{
- return sendto(rtpSocket->mFd, buffer, length, MSG_NOSIGNAL,
- (sockaddr *)&rtpSocket->mRemote, sizeof(rtpSocket->mRemote));
-}
-
-int receive(RtpSocket *rtpSocket, void *buffer, int length, timeval *deadline)
-{
- int flag = MSG_TRUNC | MSG_DONTWAIT;
- if (deadline != NULL) {
- timeval timeout;
- if (gettimeofday(&timeout, NULL) != 0) {
- return -1;
- }
-
- int remain = (deadline->tv_sec - timeout.tv_sec) * 1000000 +
- deadline->tv_usec - timeout.tv_usec;
- if (remain <= 0) {
- return 0;
- }
-
- if (remain < 1000000) {
- timeout.tv_sec = 0;
- timeout.tv_usec = remain;
- } else {
- timeout.tv_sec = remain / 1000000;
- timeout.tv_usec = remain - timeout.tv_sec * 1000000;
- }
- if (setsockopt(rtpSocket->mFd, SOL_SOCKET, SO_RCVTIMEO, &timeout,
- sizeof(timeout)) != 0) {
- return -1;
- }
- flag ^= MSG_DONTWAIT;
- }
-
- length = recv(rtpSocket->mFd, buffer, length, flag);
- if (length == -1 && (errno == EAGAIN || errno == EINTR)) {
- return 0;
- }
- return length;
-}
-
-//------------------------------------------------------------------------------
-
-static void throwSocketException(JNIEnv *env, int error)
-{
- jniThrowException(env, "java/net/SocketException", strerror(error));
-}
-
-static int parse(JNIEnv *env, jstring jAddress, jint port, sockaddr_storage *ss)
-{
- if (jAddress == NULL) {
- jniThrowNullPointerException(env, "address");
- return -1;
- }
- if (port < 0 || port > 65535) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "port");
- return -1;
- }
- const char *address = env->GetStringUTFChars(jAddress, NULL);
- if (address == NULL) {
- // Exception already thrown.
- return -1;
- }
- memset(ss, 0, sizeof(*ss));
-
- sockaddr_in *sin = (sockaddr_in *)ss;
- if (inet_pton(AF_INET, address, &(sin->sin_addr)) > 0) {
- sin->sin_family = AF_INET;
- sin->sin_port = htons(port);
- env->ReleaseStringUTFChars(jAddress, address);
- return 0;
- }
-
- sockaddr_in6 *sin6 = (sockaddr_in6 *)ss;
- if (inet_pton(AF_INET6, address, &(sin6->sin6_addr)) > 0) {
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = htons(port);
- env->ReleaseStringUTFChars(jAddress, address);
- return 0;
- }
-
- env->ReleaseStringUTFChars(jAddress, address);
- jniThrowException(env, "java/lang/IllegalArgumentException", "address");
- return -1;
-}
-
-static jint create(JNIEnv *env, jobject thiz, jstring jAddress)
-{
- sockaddr_storage ss;
- if (parse(env, jAddress, 0, &ss) < 0) {
- // Exception already thrown.
- return -1;
- }
-
- int fd = socket(ss.ss_family, SOCK_DGRAM, 0);
- socklen_t len = sizeof(ss);
- if (fd == -1 || bind(fd, (sockaddr *)&ss, sizeof(ss)) != 0 ||
- getsockname(fd, (sockaddr *)&ss, &len) != 0) {
- throwSocketException(env, errno);
- close(fd);
- return -1;
- }
-
- uint16_t *p = (ss.ss_family == AF_INET ?
- &((sockaddr_in *)&ss)->sin_port : &((sockaddr_in6 *)&ss)->sin6_port);
- uint16_t port = ntohs(*p);
- if ((port & 1) == 0) {
- env->SetIntField(thiz, gNative, (int)new RtpSocket(fd, &ss));
- return port;
- }
- close(fd);
-
- fd = socket(ss.ss_family, SOCK_DGRAM, 0);
- if (fd != -1) {
- uint16_t delta = port << 1;
- ++port;
-
- for (int i = 0; i < 1000; ++i) {
- do {
- port += delta;
- } while (port < 1024);
- *p = htons(port);
-
- if (bind(fd, (sockaddr *)&ss, sizeof(ss)) == 0) {
- env->SetIntField(thiz, gNative, (int)new RtpSocket(fd, &ss));
- return port;
- }
- }
- }
-
- throwSocketException(env, errno);
- close(fd);
- return -1;
-}
-
-static void associate(JNIEnv *env, jobject thiz, jstring jAddress, jint port)
-{
- RtpSocket *rtpSocket = getRtpSocket(env, thiz, false);
- if (rtpSocket == NULL) {
- // Exception already thrown.
- return;
- }
- sockaddr_storage ss;
- if (parse(env, jAddress, port, &ss) < 0) {
- // Exception already thrown.
- return;
- }
- if (rtpSocket->mFamily != ss.ss_family) {
- throwSocketException(env, EAFNOSUPPORT);
- return;
- }
- rtpSocket->mRemote = ss;
-}
-
-static void release(JNIEnv *env, jobject thiz)
-{
- delete (RtpSocket *)env->GetIntField(thiz, gNative);
-}
-
-//------------------------------------------------------------------------------
-
-static JNINativeMethod gMethods[] = {
- {"create", "(Ljava/lang/String;)I", (void *)create},
- {"associate", "(Ljava/lang/String;I)V", (void *)associate},
- {"release", "()V", (void *)release},
-};
-
-int registerRtpSocket(JNIEnv *env)
-{
- jclass clazz;
- if ((clazz = env->FindClass("com/android/sip/rtp/RtpSocket")) == NULL ||
- (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
- env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
- LOGE("JNI registration failed");
- return -1;
- }
- return 0;
-}
diff --git a/src/jni/rtp/RtpSocket.h b/src/jni/rtp/RtpSocket.h
deleted file mode 100644
index af1e558..0000000
--- a/src/jni/rtp/RtpSocket.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __RTP_SOCKET_H__
-#define __RTP_SOCKET_H__
-
-#include "jni.h"
-
-struct RtpSocket;
-
-// Returns NULL and throws an exception if an error occurs.
-RtpSocket *getRtpSocket(JNIEnv *env, jobject jRtpSocket, bool associated);
-
-// Returns the number of bytes sent or -1 if an error occurs. The error code
-// can be found in errno.
-int send(RtpSocket *rtpSocket, void *buffer, int length);
-
-// Returns the REAL LENGTH of the packet received, 0 if deadline is reached,
-// or -1 if an error occurs. The error code can be found in errno.
-int receive(RtpSocket *rtpSocket, void *buffer, int length, timeval *deadline);
-
-#endif
diff --git a/src/jni/rtp/libsiprtp.cpp b/src/jni/rtp/libsiprtp.cpp
deleted file mode 100644
index 46b7f98..0000000
--- a/src/jni/rtp/libsiprtp.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-
-#include "jni.h"
-
-extern int registerRtpSocket(JNIEnv *env);
-extern int registerAudioStream(JNIEnv *env);
-
-__attribute__((visibility("default")))
-jint JNI_OnLoad(JavaVM *vm, void *reserved)
-{
- JNIEnv *env = NULL;
- if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK ||
- registerRtpSocket(env) < 0 || registerAudioStream(env) < 0) {
- return -1;
- }
- return JNI_VERSION_1_4;
-}
diff --git a/src/jni/rtp_jni/Android.mk b/src/jni/rtp_jni/Android.mk
deleted file mode 100644
index 46ac19d..0000000
--- a/src/jni/rtp_jni/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := librtp_jni
-
-LOCAL_SRC_FILES := \
- AudioCodec.cpp \
- AudioGroup.cpp \
- RtpStream.cpp \
- util.cpp \
- rtp_jni.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libnativehelper \
- libcutils \
- libutils \
- libmedia
-
-LOCAL_STATIC_LIBRARIES :=
-
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
-
-LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_PRELINK_MODULE := false
-
-# include $(BUILD_SHARED_LIBRARY)
diff --git a/src/jni/rtp_jni/AudioCodec.cpp b/src/jni/rtp_jni/AudioCodec.cpp
deleted file mode 100644
index ddd07fc..0000000
--- a/src/jni/rtp_jni/AudioCodec.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyrightm (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string.h>
-
-#include "AudioCodec.h"
-
-namespace {
-
-int8_t gExponents[128] = {
- 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-};
-
-//------------------------------------------------------------------------------
-
-class UlawCodec : public AudioCodec
-{
-public:
- bool set(int sampleRate, int sampleCount) {
- mSampleCount = sampleCount;
- return sampleCount > 0;
- }
- int encode(void *payload, int16_t *samples);
- int decode(int16_t *samples, void *payload, int length);
-private:
- int mSampleCount;
-};
-
-int UlawCodec::encode(void *payload, int16_t *samples)
-{
- int8_t *ulaws = (int8_t *)payload;
- for (int i = 0; i < mSampleCount; ++i) {
- int sample = samples[i];
- int sign = (sample >> 8) & 0x80;
- if (sample < 0) {
- sample = -sample;
- }
- sample += 132;
- if (sample > 32767) {
- sample = 32767;
- }
- int exponent = gExponents[sample >> 8];
- int mantissa = (sample >> (exponent + 3)) & 0x0F;
- ulaws[i] = ~(sign | (exponent << 4) | mantissa);
- }
- return mSampleCount;
-}
-
-int UlawCodec::decode(int16_t *samples, void *payload, int length)
-{
- int8_t *ulaws = (int8_t *)payload;
- for (int i = 0; i < length; ++i) {
- int ulaw = ~ulaws[i];
- int exponent = (ulaw >> 4) & 0x07;
- int mantissa = ulaw & 0x0F;
- int sample = (((mantissa << 3) + 132) << exponent) - 132;
- samples[i] = (ulaw < 0 ? -sample : sample);
- }
- return length;
-}
-
-AudioCodec *newUlawCodec()
-{
- return new UlawCodec;
-}
-
-//------------------------------------------------------------------------------
-
-class AlawCodec : public AudioCodec
-{
-public:
- bool set(int sampleRate, int sampleCount) {
- mSampleCount = sampleCount;
- return sampleCount > 0;
- }
- int encode(void *payload, int16_t *samples);
- int decode(int16_t *samples, void *payload, int length);
-private:
- int mSampleCount;
-};
-
-int AlawCodec::encode(void *payload, int16_t *samples)
-{
- int8_t *alaws = (int8_t *)payload;
- for (int i = 0; i < mSampleCount; ++i) {
- int sample = samples[i];
- int sign = (sample >> 8) & 0x80;
- if (sample < 0) {
- sample = -sample;
- }
- if (sample > 32767) {
- sample = 32767;
- }
- int exponent = gExponents[sample >> 8];
- int mantissa = (sample >> (exponent == 0 ? 4 : exponent + 3)) & 0x0F;
- alaws[i] = (sign | (exponent << 4) | mantissa) ^ 0xD5;
- }
- return mSampleCount;
-}
-
-int AlawCodec::decode(int16_t *samples, void *payload, int length)
-{
- int8_t *alaws = (int8_t *)payload;
- for (int i = 0; i < length; ++i) {
- int alaw = alaws[i] ^ 0x55;
- int exponent = (alaw >> 4) & 0x07;
- int mantissa = alaw & 0x0F;
- int sample = (exponent == 0 ? (mantissa << 4) + 8 :
- ((mantissa << 3) + 132) << exponent);
- samples[i] = (alaw < 0 ? sample : -sample);
- }
- return length;
-}
-
-AudioCodec *newAlawCodec()
-{
- return new AlawCodec;
-}
-
-struct AudioCodecType {
- const char *name;
- AudioCodec *(*create)();
-} gAudioCodecTypes[] = {
- {"PCMA", newAlawCodec},
- {"PCMU", newUlawCodec},
- {NULL, NULL},
-};
-
-} // namespace
-
-AudioCodec *newAudioCodec(const char *codecName)
-{
- AudioCodecType *type = gAudioCodecTypes;
- while (type->name != NULL) {
- if (strcmp(codecName, type->name) == 0) {
- return type->create();
- }
- ++type;
- }
- return NULL;
-}
diff --git a/src/jni/rtp_jni/AudioCodec.h b/src/jni/rtp_jni/AudioCodec.h
deleted file mode 100644
index 797494c..0000000
--- a/src/jni/rtp_jni/AudioCodec.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyrightm (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#ifndef __AUDIO_CODEC_H__
-#define __AUDIO_CODEC_H__
-
-class AudioCodec
-{
-public:
- virtual ~AudioCodec() {}
- // Returns true if initialization succeeds.
- virtual bool set(int sampleRate, int sampleCount) = 0;
- // Returns the length of payload in bytes.
- virtual int encode(void *payload, int16_t *samples) = 0;
- // Returns the number of decoded samples.
- virtual int decode(int16_t *samples, void *payload, int length) = 0;
-};
-
-AudioCodec *newAudioCodec(const char *codecName);
-
-#endif
diff --git a/src/jni/rtp_jni/AudioGroup.cpp b/src/jni/rtp_jni/AudioGroup.cpp
deleted file mode 100644
index fc1ed9b..0000000
--- a/src/jni/rtp_jni/AudioGroup.cpp
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <time.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-#define LOG_TAG "AudioGroup"
-#include <cutils/atomic.h>
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-#include <utils/SystemClock.h>
-#include <media/AudioSystem.h>
-#include <media/AudioRecord.h>
-#include <media/AudioTrack.h>
-#include <media/mediarecorder.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-
-#include "AudioCodec.h"
-
-extern int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss);
-
-namespace {
-
-using namespace android;
-
-int gRandom = -1;
-
-// We use a circular array to implement jitter buffer. The simplest way is doing
-// a modulo operation on the index while accessing the array. However modulo can
-// be expensive on some platforms, such as ARM. Thus we round up the size of the
-// array to the nearest power of 2 and then use bitwise-and instead of modulo.
-// Currently we make it 256ms long and assume packet interval is 32ms or less.
-// The first 64ms is the place where samples get mixed. The rest 192ms is the
-// real jitter buffer. For a stream at 8000Hz it takes 4096 bytes. These numbers
-// are chosen by experiments and each of them can be adjusted as needed.
-
-// Other notes:
-// + We use elapsedRealtime() to get the time. Since we use 32bit variables
-// instead of 64bit ones, comparison must be done by subtraction.
-// + Sampling rate must be multiple of 1000Hz, and packet length must be in
-// milliseconds. No floating points.
-// + If we cannot get enough CPU, we drop samples and simulate packet loss.
-// + Resampling is not done yet, so streams in one group must use the same rate.
-// For the first release we might only support 8kHz and 16kHz.
-
-class AudioStream
-{
-public:
- AudioStream();
- ~AudioStream();
- bool set(int mode, int socket, sockaddr_storage *remote,
- const char *codecName, int sampleRate, int sampleCount,
- int codecType, int dtmfType);
-
- void sendDtmf(int event);
- bool mix(int32_t *output, int head, int tail, int sampleRate);
- void encode(int tick, AudioStream *chain);
- void decode(int tick);
-
-private:
- enum {
- NORMAL = 0,
- SEND_ONLY = 1,
- RECEIVE_ONLY = 2,
- LAST_MODE = 2,
- };
-
- int mMode;
- int mSocket;
- sockaddr_storage mRemote;
- AudioCodec *mCodec;
- uint32_t mCodecMagic;
- uint32_t mDtmfMagic;
-
- int mTick;
- int mSampleRate;
- int mSampleCount;
- int mInterval;
-
- int16_t *mBuffer;
- int mBufferMask;
- int mBufferHead;
- int mBufferTail;
- int mLatencyScore;
-
- uint16_t mSequence;
- uint32_t mTimestamp;
- uint32_t mSsrc;
-
- int mDtmfEvent;
- int mDtmfStart;
-
- AudioStream *mNext;
-
- friend class AudioGroup;
-};
-
-AudioStream::AudioStream()
-{
- mSocket = -1;
- mCodec = NULL;
- mBuffer = NULL;
- mNext = NULL;
-}
-
-AudioStream::~AudioStream()
-{
- close(mSocket);
- delete mCodec;
- delete [] mBuffer;
- LOGD("stream[%d] is dead", mSocket);
-}
-
-bool AudioStream::set(int mode, int socket, sockaddr_storage *remote,
- const char *codecName, int sampleRate, int sampleCount,
- int codecType, int dtmfType)
-{
- if (mode < 0 || mode > LAST_MODE) {
- return false;
- }
- mMode = mode;
-
- if (codecName) {
- mRemote = *remote;
- mCodec = newAudioCodec(codecName);
- if (!mCodec || !mCodec->set(sampleRate, sampleCount)) {
- return false;
- }
- }
-
- mCodecMagic = (0x8000 | codecType) << 16;
- mDtmfMagic = (dtmfType == -1) ? 0 : (0x8000 | dtmfType) << 16;
-
- mTick = elapsedRealtime();
- mSampleRate = sampleRate / 1000;
- mSampleCount = sampleCount;
- mInterval = mSampleCount / mSampleRate;
-
- // Allocate jitter buffer.
- for (mBufferMask = 8192; mBufferMask < sampleRate; mBufferMask <<= 1);
- mBufferMask >>= 2;
- mBuffer = new int16_t[mBufferMask];
- --mBufferMask;
- mBufferHead = 0;
- mBufferTail = 0;
- mLatencyScore = 0;
-
- // Initialize random bits.
- read(gRandom, &mSequence, sizeof(mSequence));
- read(gRandom, &mTimestamp, sizeof(mTimestamp));
- read(gRandom, &mSsrc, sizeof(mSsrc));
-
- mDtmfEvent = -1;
- mDtmfStart = 0;
-
- // Only take over the socket when succeeded.
- mSocket = socket;
-
- LOGD("stream[%d] is configured as %s %dkHz %dms", mSocket,
- (codecName ? codecName : "RAW"), mSampleRate, mInterval);
- return true;
-}
-
-void AudioStream::sendDtmf(int event)
-{
- if (mDtmfMagic != 0) {
- mDtmfEvent = event << 24;
- mDtmfStart = mTimestamp + mSampleCount;
- }
-}
-
-bool AudioStream::mix(int32_t *output, int head, int tail, int sampleRate)
-{
- if (mMode == SEND_ONLY) {
- return false;
- }
-
- if (head - mBufferHead < 0) {
- head = mBufferHead;
- }
- if (tail - mBufferTail > 0) {
- tail = mBufferTail;
- }
- if (tail - head <= 0) {
- return false;
- }
-
- head *= mSampleRate;
- tail *= mSampleRate;
-
- if (sampleRate == mSampleRate) {
- for (int i = head; i - tail < 0; ++i) {
- output[i - head] += mBuffer[i & mBufferMask];
- }
- } else {
- // TODO: implement resampling.
- return false;
- }
- return true;
-}
-
-void AudioStream::encode(int tick, AudioStream *chain)
-{
- if (tick - mTick >= mInterval) {
- // We just missed the train. Pretend that packets in between are lost.
- int skipped = (tick - mTick) / mInterval;
- mTick += skipped * mInterval;
- mSequence += skipped;
- mTimestamp += skipped * mSampleCount;
- LOGD("stream[%d] skips %d packets", mSocket, skipped);
- }
-
- tick = mTick;
- mTick += mInterval;
- ++mSequence;
- mTimestamp += mSampleCount;
-
- if (mMode == RECEIVE_ONLY) {
- return;
- }
-
- // If there is an ongoing DTMF event, send it now.
- if (mDtmfEvent != -1) {
- int duration = mTimestamp - mDtmfStart;
- // Make sure duration is reasonable.
- if (duration >= 0 && duration < mSampleRate * 100) {
- duration += mSampleCount;
- int32_t buffer[4] = {
- htonl(mDtmfMagic | mSequence),
- htonl(mDtmfStart),
- mSsrc,
- htonl(mDtmfEvent | duration),
- };
- if (duration >= mSampleRate * 100) {
- buffer[3] |= htonl(1 << 23);
- mDtmfEvent = -1;
- }
- sendto(mSocket, buffer, sizeof(buffer), MSG_DONTWAIT,
- (sockaddr *)&mRemote, sizeof(mRemote));
- return;
- }
- mDtmfEvent = -1;
- }
-
- // It is time to mix streams.
- bool mixed = false;
- int32_t buffer[mSampleCount + 3];
- memset(buffer, 0, sizeof(buffer));
- while (chain) {
- if (chain != this &&
- chain->mix(buffer, tick - mInterval, tick, mSampleRate)) {
- mixed = true;
- }
- chain = chain->mNext;
- }
- if (!mixed) {
- LOGD("stream[%d] no data", mSocket);
- return;
- }
-
- // Cook the packet and send it out.
- int16_t samples[mSampleCount];
- for (int i = 0; i < mSampleCount; ++i) {
- int32_t sample = buffer[i];
- if (sample < -32768) {
- sample = -32768;
- }
- if (sample > 32767) {
- sample = 32767;
- }
- samples[i] = sample;
- }
- if (!mCodec) {
- // Special case for device stream.
- send(mSocket, samples, sizeof(samples), MSG_DONTWAIT);
- return;
- }
-
- buffer[0] = htonl(mCodecMagic | mSequence);
- buffer[1] = htonl(mTimestamp);
- buffer[2] = mSsrc;
- int length = mCodec->encode(&buffer[3], samples);
- if (length <= 0) {
- LOGD("stream[%d] encoder error", mSocket);
- return;
- }
- sendto(mSocket, buffer, length + 12, MSG_DONTWAIT, (sockaddr *)&mRemote,
- sizeof(mRemote));
-}
-
-void AudioStream::decode(int tick)
-{
- char c;
- if (mMode == SEND_ONLY) {
- recv(mSocket, &c, 1, MSG_DONTWAIT);
- return;
- }
-
- // Make sure mBufferHead and mBufferTail are reasonable.
- if ((unsigned int)(tick + 256 - mBufferHead) > 1024) {
- mBufferHead = tick - 64;
- mBufferTail = mBufferHead;
- }
-
- if (tick - mBufferHead > 64) {
- // Throw away outdated samples.
- mBufferHead = tick - 64;
- if (mBufferTail - mBufferHead < 0) {
- mBufferTail = mBufferHead;
- }
- }
-
- if (mBufferTail - tick <= 80) {
- mLatencyScore = tick;
- } else if (tick - mLatencyScore >= 5000) {
- // Reset the jitter buffer to 40ms if the latency keeps larger than 80ms
- // in the past 5s. This rarely happens, so let us just keep it simple.
- LOGD("stream[%d] latency control", mSocket);
- mBufferTail = tick + 40;
- }
-
- if (mBufferTail - mBufferHead > 256 - mInterval) {
- // Buffer overflow. Drop the packet.
- LOGD("stream[%d] buffer overflow", mSocket);
- recv(mSocket, &c, 1, MSG_DONTWAIT);
- return;
- }
-
- // Receive the packet and decode it.
- int16_t samples[mSampleCount];
- int length = 0;
- if (!mCodec) {
- // Special case for device stream.
- length = recv(mSocket, samples, sizeof(samples),
- MSG_TRUNC | MSG_DONTWAIT) >> 1;
- } else {
- __attribute__((aligned(4))) uint8_t buffer[2048];
- length = recv(mSocket, buffer, sizeof(buffer),
- MSG_TRUNC | MSG_DONTWAIT);
-
- // Do we need to check SSRC, sequence, and timestamp? They are not
- // reliable but at least they can be used to identity duplicates?
- if (length < 12 || length > (int)sizeof(buffer) ||
- (ntohl(*(uint32_t *)buffer) & 0xC07F0000) != mCodecMagic) {
- LOGD("stream[%d] malformed packet", mSocket);
- return;
- }
- int offset = 12 + ((buffer[0] & 0x0F) << 2);
- if ((buffer[0] & 0x10) != 0) {
- offset += 4 + (ntohs(*(uint16_t *)&buffer[offset + 2]) << 2);
- }
- if ((buffer[0] & 0x20) != 0) {
- length -= buffer[length - 1];
- }
- length -= offset;
- if (length >= 0) {
- length = mCodec->decode(samples, &buffer[offset], length);
- }
- }
- if (length != mSampleCount) {
- LOGD("stream[%d] decoder error", mSocket);
- return;
- }
-
- if (tick - mBufferTail > 0) {
- // Buffer underrun. Reset the jitter buffer to 40ms.
- LOGD("stream[%d] buffer underrun", mSocket);
- if (mBufferTail - mBufferHead <= 0) {
- mBufferHead = tick + 40;
- mBufferTail = mBufferHead;
- } else {
- int tail = (tick + 40) * mSampleRate;
- for (int i = mBufferTail * mSampleRate; i - tail < 0; ++i) {
- mBuffer[i & mBufferMask] = 0;
- }
- mBufferTail = tick + 40;
- }
- }
-
- // Append to the jitter buffer.
- int tail = mBufferTail * mSampleRate;
- for (int i = 0; i < mSampleCount; ++i) {
- mBuffer[tail & mBufferMask] = samples[i];
- ++tail;
- }
- mBufferTail += mInterval;
-}
-
-//------------------------------------------------------------------------------
-
-class AudioGroup
-{
-public:
- AudioGroup();
- ~AudioGroup();
- bool set(int sampleRate, int sampleCount);
-
- bool setMode(int mode);
- bool sendDtmf(int event);
- bool add(AudioStream *stream);
- bool remove(int socket);
-
-private:
- enum {
- ON_HOLD = 0,
- MUTED = 1,
- NORMAL = 2,
- EC_ENABLED = 3,
- LAST_MODE = 3,
- };
- int mMode;
- AudioStream *mChain;
- int mEventQueue;
- volatile int mDtmfEvent;
-
- int mSampleCount;
- int mDeviceSocket;
- AudioTrack mTrack;
- AudioRecord mRecord;
-
- bool networkLoop();
- bool deviceLoop();
-
- class NetworkThread : public Thread
- {
- public:
- NetworkThread(AudioGroup *group) : Thread(false), mGroup(group) {}
-
- bool start()
- {
- if (run("Network", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
- LOGE("cannot start network thread");
- return false;
- }
- return true;
- }
-
- private:
- AudioGroup *mGroup;
- bool threadLoop()
- {
- return mGroup->networkLoop();
- }
- };
- sp<NetworkThread> mNetworkThread;
-
- class DeviceThread : public Thread
- {
- public:
- DeviceThread(AudioGroup *group) : Thread(false), mGroup(group) {}
-
- bool start()
- {
- char c;
- while (recv(mGroup->mDeviceSocket, &c, 1, MSG_DONTWAIT) == 1);
-
- if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
- LOGE("cannot start device thread");
- return false;
- }
- return true;
- }
-
- private:
- AudioGroup *mGroup;
- bool threadLoop()
- {
- return mGroup->deviceLoop();
- }
- };
- sp<DeviceThread> mDeviceThread;
-};
-
-AudioGroup::AudioGroup()
-{
- mMode = ON_HOLD;
- mChain = NULL;
- mEventQueue = -1;
- mDtmfEvent = -1;
- mDeviceSocket = -1;
- mNetworkThread = new NetworkThread(this);
- mDeviceThread = new DeviceThread(this);
-}
-
-AudioGroup::~AudioGroup()
-{
- mNetworkThread->requestExitAndWait();
- mDeviceThread->requestExitAndWait();
- mTrack.stop();
- mRecord.stop();
- close(mEventQueue);
- close(mDeviceSocket);
- while (mChain) {
- AudioStream *next = mChain->mNext;
- delete mChain;
- mChain = next;
- }
- LOGD("group[%d] is dead", mDeviceSocket);
-}
-
-#define FROYO_COMPATIBLE
-#ifdef FROYO_COMPATIBLE
-
-// Copied from AudioRecord.cpp.
-status_t AudioRecord_getMinFrameCount(
- int* frameCount,
- uint32_t sampleRate,
- int format,
- int channelCount)
-{
- size_t size = 0;
- if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &size)
- != NO_ERROR) {
- LOGE("AudioSystem could not query the input buffer size.");
- return NO_INIT;
- }
-
- if (size == 0) {
- LOGE("Unsupported configuration: sampleRate %d, format %d, channelCount %d",
- sampleRate, format, channelCount);
- return BAD_VALUE;
- }
-
- // We double the size of input buffer for ping pong use of record buffer.
- size <<= 1;
-
- if (AudioSystem::isLinearPCM(format)) {
- size /= channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1);
- }
-
- *frameCount = size;
- return NO_ERROR;
-}
-
-// Copied from AudioTrack.cpp.
-status_t AudioTrack_getMinFrameCount(
- int* frameCount,
- int streamType,
- uint32_t sampleRate)
-{
- int afSampleRate;
- if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
- return NO_INIT;
- }
- int afFrameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
- return NO_INIT;
- }
- uint32_t afLatency;
- if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
- return NO_INIT;
- }
-
- // Ensure that buffer depth covers at least audio hardware latency
- uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
- if (minBufCount < 2) minBufCount = 2;
-
- *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
- afFrameCount * minBufCount * sampleRate / afSampleRate;
- return NO_ERROR;
-}
-
-#endif
-
-bool AudioGroup::set(int sampleRate, int sampleCount)
-{
- mEventQueue = epoll_create(2);
- if (mEventQueue == -1) {
- LOGE("epoll_create: %s", strerror(errno));
- return false;
- }
-
- mSampleCount = sampleCount;
-
- // Find out the frame count for AudioTrack and AudioRecord.
- int output = 0;
- int input = 0;
-#ifdef FROYO_COMPATIBLE
- if (AudioTrack_getMinFrameCount(&output, AudioSystem::VOICE_CALL,
- sampleRate) != NO_ERROR || output <= 0 ||
- AudioRecord_getMinFrameCount(&input, sampleRate,
- AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
- LOGE("cannot compute frame count");
- return false;
- }
-#else
- if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
- sampleRate) != NO_ERROR || output <= 0 ||
- AudioRecord::getMinFrameCount(&input, sampleRate,
- AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
- LOGE("cannot compute frame count");
- return false;
- }
-#endif
- LOGD("reported frame count: output %d, input %d", output, input);
-
- output = (output + sampleCount - 1) / sampleCount * sampleCount;
- input = (input + sampleCount - 1) / sampleCount * sampleCount;
- if (input < output * 2) {
- input = output * 2;
- }
- LOGD("adjusted frame count: output %d, input %d", output, input);
-
- // Initialize AudioTrack and AudioRecord.
- if (mTrack.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
- AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR ||
- mRecord.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
- AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
- LOGE("cannot initialize audio device");
- return false;
- }
- LOGD("latency: output %d, input %d", mTrack.latency(), mRecord.latency());
-
- // TODO: initialize echo canceler here.
-
- // Create device socket.
- int pair[2];
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
- LOGE("socketpair: %s", strerror(errno));
- return false;
- }
- mDeviceSocket = pair[0];
-
- // Create device stream.
- mChain = new AudioStream;
- if (!mChain->set(AudioStream::NORMAL, pair[1], NULL, NULL,
- sampleRate, sampleCount, -1, -1)) {
- close(pair[1]);
- LOGE("cannot initialize device stream");
- return false;
- }
-
- // Give device socket a reasonable timeout and buffer size.
- timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
- if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) ||
- setsockopt(pair[0], SOL_SOCKET, SO_RCVBUF, &output, sizeof(output)) ||
- setsockopt(pair[1], SOL_SOCKET, SO_SNDBUF, &output, sizeof(output))) {
- LOGE("setsockopt: %s", strerror(errno));
- return false;
- }
-
- // Add device stream into event queue.
- epoll_event event;
- event.events = EPOLLIN;
- event.data.ptr = mChain;
- if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, pair[1], &event)) {
- LOGE("epoll_ctl: %s", strerror(errno));
- return false;
- }
-
- // Anything else?
- LOGD("stream[%d] joins group[%d]", pair[1], pair[0]);
- return true;
-}
-
-bool AudioGroup::setMode(int mode)
-{
- if (mode < 0 || mode > LAST_MODE) {
- return false;
- }
- if (mMode == mode) {
- return true;
- }
-
- LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
- mMode = mode;
-
- mDeviceThread->requestExitAndWait();
- if (mode == ON_HOLD) {
- mTrack.stop();
- mRecord.stop();
- return true;
- }
-
- mTrack.start();
- if (mode == MUTED) {
- mRecord.stop();
- } else {
- mRecord.start();
- }
-
- if (!mDeviceThread->start()) {
- mTrack.stop();
- mRecord.stop();
- return false;
- }
- return true;
-}
-
-bool AudioGroup::sendDtmf(int event)
-{
- if (event < 0 || event > 15) {
- return false;
- }
-
- // DTMF is rarely used, so we try to make it as lightweight as possible.
- // Using volatile might be dodgy, but using a pipe or pthread primitives
- // or stop-set-restart threads seems too heavy. Will investigate later.
- timespec ts;
- ts.tv_sec = 0;
- ts.tv_nsec = 100000000;
- for (int i = 0; mDtmfEvent != -1 && i < 20; ++i) {
- nanosleep(&ts, NULL);
- }
- if (mDtmfEvent != -1) {
- return false;
- }
- mDtmfEvent = event;
- nanosleep(&ts, NULL);
- return true;
-}
-
-bool AudioGroup::add(AudioStream *stream)
-{
- mNetworkThread->requestExitAndWait();
-
- epoll_event event;
- event.events = EPOLLIN;
- event.data.ptr = stream;
- if (epoll_ctl(mEventQueue, EPOLL_CTL_ADD, stream->mSocket, &event)) {
- LOGE("epoll_ctl: %s", strerror(errno));
- return false;
- }
-
- stream->mNext = mChain->mNext;
- mChain->mNext = stream;
- if (!mNetworkThread->start()) {
- // Only take over the stream when succeeded.
- mChain->mNext = stream->mNext;
- return false;
- }
-
- LOGD("stream[%d] joins group[%d]", stream->mSocket, mDeviceSocket);
- return true;
-}
-
-bool AudioGroup::remove(int socket)
-{
- mNetworkThread->requestExitAndWait();
-
- for (AudioStream *stream = mChain; stream->mNext; stream = stream->mNext) {
- AudioStream *target = stream->mNext;
- if (target->mSocket == socket) {
- stream->mNext = target->mNext;
- LOGD("stream[%d] leaves group[%d]", socket, mDeviceSocket);
- delete target;
- break;
- }
- }
-
- // Do not start network thread if there is only one stream.
- if (!mChain->mNext || !mNetworkThread->start()) {
- return false;
- }
- return true;
-}
-
-bool AudioGroup::networkLoop()
-{
- int tick = elapsedRealtime();
- int deadline = tick + 10;
- int count = 0;
-
- for (AudioStream *stream = mChain; stream; stream = stream->mNext) {
- if (!stream->mTick || tick - stream->mTick >= 0) {
- stream->encode(tick, mChain);
- }
- if (deadline - stream->mTick > 0) {
- deadline = stream->mTick;
- }
- ++count;
- }
-
- if (mDtmfEvent != -1) {
- int event = mDtmfEvent;
- for (AudioStream *stream = mChain; stream; stream = stream->mNext) {
- stream->sendDtmf(event);
- }
- mDtmfEvent = -1;
- }
-
- deadline -= tick;
- if (deadline < 1) {
- deadline = 1;
- }
-
- epoll_event events[count];
- count = epoll_wait(mEventQueue, events, count, deadline);
- if (count == -1) {
- LOGE("epoll_wait: %s", strerror(errno));
- return false;
- }
- for (int i = 0; i < count; ++i) {
- ((AudioStream *)events[i].data.ptr)->decode(tick);
- }
-
- return true;
-}
-
-bool AudioGroup::deviceLoop()
-{
- int16_t output[mSampleCount];
-
- if (recv(mDeviceSocket, output, sizeof(output), 0) <= 0) {
- memset(output, 0, sizeof(output));
- }
- if (mTrack.write(output, sizeof(output)) != (int)sizeof(output)) {
- LOGE("cannot write to AudioTrack");
- return false;
- }
-
- if (mMode != MUTED) {
- uint32_t frameCount = mRecord.frameCount();
- AudioRecord::Buffer input;
- input.frameCount = frameCount;
-
- if (mRecord.obtainBuffer(&input, -1) != NO_ERROR) {
- LOGE("cannot read from AudioRecord");
- return false;
- }
-
- if (input.frameCount < (uint32_t)mSampleCount) {
- input.frameCount = 0;
- } else {
- if (mMode == NORMAL) {
- send(mDeviceSocket, input.i8, sizeof(output), MSG_DONTWAIT);
- } else {
- // TODO: Echo canceller runs here.
- send(mDeviceSocket, input.i8, sizeof(output), MSG_DONTWAIT);
- }
- if (input.frameCount < frameCount) {
- input.frameCount = mSampleCount;
- }
- }
-
- mRecord.releaseBuffer(&input);
- }
-
- return true;
-}
-
-//------------------------------------------------------------------------------
-
-static jfieldID gNative;
-static jfieldID gMode;
-
-jint add(JNIEnv *env, jobject thiz, jint mode,
- jint socket, jstring jRemoteAddress, jint remotePort,
- jstring jCodecName, jint sampleRate, jint sampleCount,
- jint codecType, jint dtmfType)
-{
- const char *codecName = NULL;
- AudioStream *stream = NULL;
- AudioGroup *group = NULL;
-
- // Sanity check.
- sockaddr_storage remote;
- if (parse(env, jRemoteAddress, remotePort, &remote) < 0) {
- // Exception already thrown.
- return -1;
- }
- if (sampleRate < 0 || sampleCount < 0 || codecType < 0 || codecType > 127) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- goto error;
- }
- if (!jCodecName) {
- jniThrowNullPointerException(env, "codecName");
- return -1;
- }
- codecName = env->GetStringUTFChars(jCodecName, NULL);
- if (!codecName) {
- // Exception already thrown.
- return -1;
- }
-
- // Create audio stream.
- stream = new AudioStream;
- if (!stream->set(mode, socket, &remote, codecName, sampleRate, sampleCount,
- codecType, dtmfType)) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "cannot initialize audio stream");
- goto error;
- }
- socket = -1;
-
- // Create audio group.
- group = (AudioGroup *)env->GetIntField(thiz, gNative);
- if (!group) {
- int mode = env->GetIntField(thiz, gMode);
- group = new AudioGroup;
- if (!group->set(8000, 256) || !group->setMode(mode)) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "cannot initialize audio group");
- goto error;
- }
- }
-
- // Add audio stream into audio group.
- if (!group->add(stream)) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "cannot add audio stream");
- goto error;
- }
-
- // Succeed.
- env->SetIntField(thiz, gNative, (int)group);
- env->ReleaseStringUTFChars(jCodecName, codecName);
- return socket;
-
-error:
- delete group;
- delete stream;
- close(socket);
- env->SetIntField(thiz, gNative, NULL);
- env->ReleaseStringUTFChars(jCodecName, codecName);
- return -1;
-}
-
-void remove(JNIEnv *env, jobject thiz, jint socket)
-{
- AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
- if (group) {
- if (socket == -1 || !group->remove(socket)) {
- delete group;
- env->SetIntField(thiz, gNative, NULL);
- }
- }
-}
-
-void setMode(JNIEnv *env, jobject thiz, jint mode)
-{
- AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
- if (group && !group->setMode(mode)) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
- env->SetIntField(thiz, gMode, mode);
-}
-
-void sendDtmf(JNIEnv *env, jobject thiz, jint event)
-{
- AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
- if (group && !group->sendDtmf(event)) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- }
-}
-
-JNINativeMethod gMethods[] = {
- {"add", "(IILjava/lang/String;ILjava/lang/String;IIII)I", (void *)add},
- {"remove", "(I)V", (void *)remove},
- {"setMode", "(I)V", (void *)setMode},
- {"sendDtmf", "(I)V", (void *)sendDtmf},
-};
-
-} // namespace
-
-int registerAudioGroup(JNIEnv *env)
-{
- gRandom = open("/dev/urandom", O_RDONLY);
- if (gRandom == -1) {
- LOGE("urandom: %s", strerror(errno));
- return -1;
- }
-
- jclass clazz;
- if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL ||
- (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
- (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL ||
- env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
- LOGE("JNI registration failed");
- return -1;
- }
- return 0;
-}
diff --git a/src/jni/rtp_jni/RtpStream.cpp b/src/jni/rtp_jni/RtpStream.cpp
deleted file mode 100644
index 33b88e4..0000000
--- a/src/jni/rtp_jni/RtpStream.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-#define LOG_TAG "RtpStream"
-#include <utils/Log.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-
-extern int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss);
-
-namespace {
-
-jfieldID gNative;
-
-jint create(JNIEnv *env, jobject thiz, jstring jAddress)
-{
- env->SetIntField(thiz, gNative, -1);
-
- sockaddr_storage ss;
- if (parse(env, jAddress, 0, &ss) < 0) {
- // Exception already thrown.
- return -1;
- }
-
- int socket = ::socket(ss.ss_family, SOCK_DGRAM, 0);
- socklen_t len = sizeof(ss);
- if (socket == -1 || bind(socket, (sockaddr *)&ss, sizeof(ss)) != 0 ||
- getsockname(socket, (sockaddr *)&ss, &len) != 0) {
- jniThrowException(env, "java/net/SocketException", strerror(errno));
- ::close(socket);
- return -1;
- }
-
- uint16_t *p = (ss.ss_family == AF_INET) ?
- &((sockaddr_in *)&ss)->sin_port : &((sockaddr_in6 *)&ss)->sin6_port;
- uint16_t port = ntohs(*p);
- if ((port & 1) == 0) {
- env->SetIntField(thiz, gNative, socket);
- return port;
- }
- ::close(socket);
-
- socket = ::socket(ss.ss_family, SOCK_DGRAM, 0);
- if (socket != -1) {
- uint16_t delta = port << 1;
- ++port;
-
- for (int i = 0; i < 1000; ++i) {
- do {
- port += delta;
- } while (port < 1024);
- *p = htons(port);
-
- if (bind(socket, (sockaddr *)&ss, sizeof(ss)) == 0) {
- env->SetIntField(thiz, gNative, socket);
- return port;
- }
- }
- }
-
- jniThrowException(env, "java/net/SocketException", strerror(errno));
- ::close(socket);
- return -1;
-}
-
-jint dup(JNIEnv *env, jobject thiz)
-{
- int socket1 = env->GetIntField(thiz, gNative);
- int socket2 = ::dup(socket1);
- if (socket2 == -1) {
- jniThrowException(env, "java/lang/IllegalStateException", strerror(errno));
- }
- LOGD("dup %d to %d", socket1, socket2);
- return socket2;
-}
-
-void close(JNIEnv *env, jobject thiz)
-{
- int socket = env->GetIntField(thiz, gNative);
- ::close(socket);
- env->SetIntField(thiz, gNative, -1);
- LOGD("close %d", socket);
-}
-
-JNINativeMethod gMethods[] = {
- {"create", "(Ljava/lang/String;)I", (void *)create},
- {"dup", "()I", (void *)dup},
- {"close", "()V", (void *)close},
-};
-
-} // namespace
-
-int registerRtpStream(JNIEnv *env)
-{
- jclass clazz;
- if ((clazz = env->FindClass("android/net/rtp/RtpStream")) == NULL ||
- (gNative = env->GetFieldID(clazz, "mNative", "I")) == NULL ||
- env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
- LOGE("JNI registration failed");
- return -1;
- }
- return 0;
-}
diff --git a/src/jni/rtp_jni/rtp_jni.cpp b/src/jni/rtp_jni/rtp_jni.cpp
deleted file mode 100644
index 9f4bff9..0000000
--- a/src/jni/rtp_jni/rtp_jni.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-
-#include "jni.h"
-
-extern int registerRtpStream(JNIEnv *env);
-extern int registerAudioGroup(JNIEnv *env);
-
-__attribute__((visibility("default"))) jint JNI_OnLoad(JavaVM *vm, void *unused)
-{
- JNIEnv *env = NULL;
- if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK ||
- registerRtpStream(env) < 0 || registerAudioGroup(env) < 0) {
- return -1;
- }
- return JNI_VERSION_1_4;
-}
diff --git a/src/jni/rtp_jni/util.cpp b/src/jni/rtp_jni/util.cpp
deleted file mode 100644
index 1d702fc..0000000
--- a/src/jni/rtp_jni/util.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-
-int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss)
-{
- if (!jAddress) {
- jniThrowNullPointerException(env, "address");
- return -1;
- }
- if (port < 0 || port > 65535) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "port");
- return -1;
- }
- const char *address = env->GetStringUTFChars(jAddress, NULL);
- if (!address) {
- // Exception already thrown.
- return -1;
- }
- memset(ss, 0, sizeof(*ss));
-
- sockaddr_in *sin = (sockaddr_in *)ss;
- if (inet_pton(AF_INET, address, &(sin->sin_addr)) > 0) {
- sin->sin_family = AF_INET;
- sin->sin_port = htons(port);
- env->ReleaseStringUTFChars(jAddress, address);
- return 0;
- }
-
- sockaddr_in6 *sin6 = (sockaddr_in6 *)ss;
- if (inet_pton(AF_INET6, address, &(sin6->sin6_addr)) > 0) {
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = htons(port);
- env->ReleaseStringUTFChars(jAddress, address);
- return 0;
- }
-
- env->ReleaseStringUTFChars(jAddress, address);
- jniThrowException(env, "java/lang/IllegalArgumentException", "address");
- return -1;
-}