Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 53aa6ef7 authored by Chia-chi Yeh's avatar Chia-chi Yeh
Browse files

RTP: Prepare to unhide the APIs.

Polish things a little bit.

Change-Id: I2c3cea8b34b9c858879bc722ea1f38082ba22b8d
parent 1318af1a
Loading
Loading
Loading
Loading
+77 −33
Original line number Diff line number Diff line
@@ -21,14 +21,14 @@ import java.util.Map;

/**
 * An AudioGroup acts as a router connected to the speaker, the microphone, and
 * {@link AudioStream}s. Its pipeline has four steps. First, for each
 * AudioStream not in {@link RtpStream#MODE_SEND_ONLY}, decodes its incoming
 * packets and stores in its buffer. Then, if the microphone is enabled,
 * processes the recorded audio and stores in its buffer. Third, if the speaker
 * is enabled, mixes and playbacks buffers of all AudioStreams. Finally, for
 * each AudioStream not in {@link RtpStream#MODE_RECEIVE_ONLY}, mixes all other
 * buffers and sends back the encoded packets. An AudioGroup does nothing if
 * there is no AudioStream in it.
 * {@link AudioStream}s. Its execution loop consists of four steps. First, for
 * each AudioStream not in {@link RtpStream#MODE_SEND_ONLY}, decodes its
 * incoming packets and stores in its buffer. Then, if the microphone is
 * enabled, processes the recorded audio and stores in its buffer. Third, if the
 * speaker is enabled, mixes and playbacks buffers of all AudioStreams. Finally,
 * for each AudioStream not in {@link RtpStream#MODE_RECEIVE_ONLY}, mixes all
 * other buffers and sends back the encoded packets. An AudioGroup does nothing
 * if there is no AudioStream in it.
 *
 * <p>Few things must be noticed before using these classes. The performance is
 * highly related to the system load and the network bandwidth. Usually a
@@ -47,7 +47,12 @@ import java.util.Map;
 * modes other than {@link #MODE_ON_HOLD}. In addition, before adding an
 * AudioStream into an AudioGroup, one should always put all other AudioGroups
 * into {@link #MODE_ON_HOLD}. That will make sure the audio driver correctly
 * initialized.
 * initialized.</p>
 *
 * <p class="note">Using this class requires
 * {@link android.Manifest.permission#RECORD_AUDIO} permission.</p>
 *
 * @see AudioStream
 * @hide
 */
public class AudioGroup {
@@ -78,6 +83,8 @@ public class AudioGroup {
     */
    public static final int MODE_ECHO_SUPPRESSION = 3;

    private static final int MODE_LAST = 3;

    private final Map<AudioStream, Integer> mStreams;
    private int mMode = MODE_ON_HOLD;

@@ -93,6 +100,15 @@ public class AudioGroup {
        mStreams = new HashMap<AudioStream, Integer>();
    }

    /**
     * Returns the {@link AudioStream}s in this group.
     */
    public AudioStream[] getStreams() {
        synchronized (this) {
            return mStreams.keySet().toArray(new AudioStream[mStreams.size()]);
        }
    }

    /**
     * Returns the current mode.
     */
@@ -108,18 +124,27 @@ public class AudioGroup {
     * @param mode The mode to change to.
     * @throws IllegalArgumentException if the mode is invalid.
     */
    public synchronized native void setMode(int mode);
    public void setMode(int mode) {
        if (mode < 0 || mode > MODE_LAST) {
            throw new IllegalArgumentException("Invalid mode");
        }
        synchronized (this) {
            nativeSetMode(mode);
            mMode = mode;
        }
    }

    private native void add(int mode, int socket, String remoteAddress,
            int remotePort, String codecSpec, int dtmfType);
    private native void nativeSetMode(int mode);

    synchronized void add(AudioStream stream, AudioCodec codec, int dtmfType) {
    // Package-private method used by AudioStream.join().
    void add(AudioStream stream, AudioCodec codec, int dtmfType) {
        synchronized (this) {
            if (!mStreams.containsKey(stream)) {
                try {
                    int socket = stream.dup();
                    String codecSpec = String.format("%d %s %s", codec.type,
                            codec.rtpmap, codec.fmtp);
                add(stream.getMode(), socket,
                    nativeAdd(stream.getMode(), socket,
                            stream.getRemoteAddress().getHostAddress(),
                            stream.getRemotePort(), codecSpec, dtmfType);
                    mStreams.put(stream, socket);
@@ -128,15 +153,22 @@ public class AudioGroup {
                }
            }
        }
    }

    private native void remove(int socket);
    private native void nativeAdd(int mode, int socket, String remoteAddress,
            int remotePort, String codecSpec, int dtmfType);

    synchronized void remove(AudioStream stream) {
    // Package-private method used by AudioStream.join().
    void remove(AudioStream stream) {
        synchronized (this) {
            Integer socket = mStreams.remove(stream);
            if (socket != null) {
            remove(socket);
                nativeRemove(socket);
            }
        }
    }

    private native void nativeRemove(int socket);

    /**
     * Sends a DTMF digit to every {@link AudioStream} in this group. Currently
@@ -144,13 +176,25 @@ public class AudioGroup {
     *
     * @throws IllegalArgumentException if the event is invalid.
     */
    public native synchronized void sendDtmf(int event);
    public void sendDtmf(int event) {
        if (event < 0 || event > 15) {
            throw new IllegalArgumentException("Invalid event");
        }
        synchronized (this) {
            nativeSendDtmf(event);
        }
    }

    private native void nativeSendDtmf(int event);

    /**
     * Removes every {@link AudioStream} in this group.
     */
    public synchronized void clear() {
        remove(-1);
    public void clear() {
        synchronized (this) {
            mStreams.clear();
            nativeRemove(-1);
        }
    }

    @Override
+17 −11
Original line number Diff line number Diff line
@@ -34,8 +34,12 @@ import java.net.SocketException;
 * of the setter methods are disabled. This is designed to ease the task of
 * managing native resources. One can always make an AudioStream leave its
 * AudioGroup by calling {@link #join(AudioGroup)} with {@code null} and put it
 * back after the modification is done.
 * back after the modification is done.</p>
 *
 * <p class="note">Using this class requires
 * {@link android.Manifest.permission#INTERNET} permission.</p>
 *
 * @see RtpStream
 * @see AudioGroup
 * @hide
 */
@@ -82,6 +86,7 @@ public class AudioStream extends RtpStream {
     * @see AudioGroup
     */
    public void join(AudioGroup group) {
        synchronized (this) {
            if (mGroup == group) {
                return;
            }
@@ -94,6 +99,7 @@ public class AudioStream extends RtpStream {
                mGroup = group;
            }
        }
    }

    /**
     * Returns the {@link AudioCodec}, or {@code null} if it is not set.
+6 −1
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@ import java.net.SocketException;
/**
 * RtpStream represents the base class of streams which send and receive network
 * packets with media payloads over Real-time Transport Protocol (RTP).
 *
 * <p class="note">Using this class requires
 * {@link android.Manifest.permission#INTERNET} permission.</p>
 * @hide
 */
public class RtpStream {
@@ -43,6 +46,8 @@ public class RtpStream {
     */
    public static final int MODE_RECEIVE_ONLY = 2;

    private static final int MODE_LAST = 2;

    private final InetAddress mLocalAddress;
    private final int mLocalPort;

@@ -129,7 +134,7 @@ public class RtpStream {
        if (isBusy()) {
            throw new IllegalStateException("Busy");
        }
        if (mode != MODE_NORMAL && mode != MODE_SEND_ONLY && mode != MODE_RECEIVE_ONLY) {
        if (mode < 0 || mode > MODE_LAST) {
            throw new IllegalArgumentException("Invalid mode");
        }
        mMode = mode;
+1 −1
Original line number Diff line number Diff line
@@ -73,7 +73,7 @@ int AmrCodec::set(int sampleRate, const char *fmtp)
    }

    // Handle mode-set and octet-align.
    char *modes = (char*)strcasestr(fmtp, "mode-set=");
    const char *modes = strcasestr(fmtp, "mode-set=");
    if (modes) {
        mMode = 0;
        mModeSet = 0;
+6 −12
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ public:
    void encode(int tick, AudioStream *chain);
    void decode(int tick);

private:
    enum {
        NORMAL = 0,
        SEND_ONLY = 1,
@@ -97,7 +98,6 @@ public:
        LAST_MODE = 2,
    };

private:
    int mMode;
    int mSocket;
    sockaddr_storage mRemote;
@@ -463,6 +463,7 @@ public:
    bool add(AudioStream *stream);
    bool remove(int socket);

private:
    enum {
        ON_HOLD = 0,
        MUTED = 1,
@@ -471,7 +472,6 @@ public:
        LAST_MODE = 3,
    };

private:
    AudioStream *mChain;
    int mEventQueue;
    volatile int mDtmfEvent;
@@ -948,16 +948,10 @@ void remove(JNIEnv *env, jobject thiz, jint socket)

void setMode(JNIEnv *env, jobject thiz, jint mode)
{
    if (mode < 0 || mode > AudioGroup::LAST_MODE) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return;
    }
    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)
@@ -969,10 +963,10 @@ void sendDtmf(JNIEnv *env, jobject thiz, jint event)
}

JNINativeMethod gMethods[] = {
    {"add", "(IILjava/lang/String;ILjava/lang/String;I)V", (void *)add},
    {"remove", "(I)V", (void *)remove},
    {"setMode", "(I)V", (void *)setMode},
    {"sendDtmf", "(I)V", (void *)sendDtmf},
    {"nativeAdd", "(IILjava/lang/String;ILjava/lang/String;I)V", (void *)add},
    {"nativeRemove", "(I)V", (void *)remove},
    {"nativeSetMode", "(I)V", (void *)setMode},
    {"nativeSendDtmf", "(I)V", (void *)sendDtmf},
};

} // namespace