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

Commit 363c2ab8 authored by Chung-yih Wang's avatar Chung-yih Wang
Browse files

Move the sip related codes to framework.

Change-Id: Ib81dadc39b73325c8438f078c7251857a83834fe
parent 543f250d
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
/*
 * 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;

/** @hide */
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;
    }
}
+91 −0
Original line number Diff line number Diff line
/*
 * 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;

/**
 */
/** @hide */
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();
    }
}
+136 −0
Original line number Diff line number Diff line
/*
 * 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.
 */
/** @hide */
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;
    }
}
+173 −0
Original line number Diff line number Diff line
/*
 * 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).
 */
/** @hide */
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();
    }
}
+79 −0
Original line number Diff line number Diff line
/*
 * 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.sip;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Looper;
import android.util.Log;

// TODO: throw away this class after moving SIP classes to framework
// This class helps to get IBinder instance of a service in a blocking call.
// The method cannot be called in app's main thread as the ServiceConnection
// callback will.
class BinderHelper<T extends IInterface> {
    private Context mContext;
    private IBinder mBinder;
    private Class<T> mClass;

    BinderHelper(Context context, Class<T> klass) {
        mContext = context;
        mClass = klass;
    }

    void startService() {
        mContext.startService(new Intent(mClass.getName()));
    }

    void stopService() {
        mContext.stopService(new Intent(mClass.getName()));
    }

    IBinder getBinder() {
        // cannot call this method in app's main thread
        if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
            throw new RuntimeException(
                    "This method cannot be called in app's main thread");
        }

        final ConditionVariable cv = new ConditionVariable();
        cv.close();
        ServiceConnection c = new ServiceConnection() {
            public synchronized void onServiceConnected(
                    ComponentName className, IBinder binder) {
                Log.v("BinderHelper", "service connected!");
                mBinder = binder;
                cv.open();
                mContext.unbindService(this);
            }

            public void onServiceDisconnected(ComponentName className) {
                cv.open();
                mContext.unbindService(this);
            }
        };
        if (mContext.bindService(new Intent(mClass.getName()), c, 0)) {
            cv.block(4500);
        }
        return mBinder;
    }
}
Loading