Package im.tox.jtoxcore

Source Code of im.tox.jtoxcore.JTox

/* JTox.java
*
*  Copyright (C) 2014 Tox project All Rights Reserved.
*
*  This file is part of jToxcore
*
*  jToxcore is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  jToxcore is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with jToxcore.  If not, see <http://www.gnu.org/licenses/>.
*
*/

package im.tox.jtoxcore;

import java.io.UnsupportedEncodingException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

import im.tox.jtoxcore.callbacks.CallbackHandler;

/**
* This is the main wrapper class for the tox library. It contains wrapper
* methods for everything in the public API provided by tox.h
*
* @author sonOfRa
* @param <F>
*            Friend type for this JTox instance
*/
public class JTox<F extends ToxFriend> {

  /**
   * Maximum length of a status message in Bytes. Non-ASCII characters take
   * multiple Bytes.
   */
  public static final int TOX_MAX_STATUSMESSAGE_LENGTH = 128;

  /**
   * Maximum length of a nickname in Bytes. Non-ASCII characters take multiple
   * Bytes.
   */
  public static final int TOX_MAX_NICKNAME_LENGTH = 128;

  static {
    System.loadLibrary("jtoxcore");
  }

  /**
   * List containing all currently active tox instances
   */
  private static List<Long> validPointers = Collections.synchronizedList(new ArrayList<Long>());

  private static Map < Integer, JTox<? >> instances = new HashMap < Integer, JTox<? >> ();
  private static ReentrantLock instanceLock = new ReentrantLock();
  private static int instanceCounter = 0;
  private final int instanceNumber;

  private CallbackHandler<F> handler;
  private FriendList<F> friendList;

  /**
   * This field contains the lock used for thread safety
   */
  private final ReentrantLock lock;

  /**
   * This field contains the pointer used in all native tox_ method calls.
   */
  private final long messengerPointer;

  private final long avPointer;
  /**
   * Native call to tox_new
   *
   * @return the pointer to the messenger struct on success, 0 on failure
   */
  private native long tox_new(ToxOptions options);

  /**
   * Creates a new instance of JTox and stores the pointer to the internal
   * struct in messengerPointer.
   *
   * @param friendList
   *            the friendlist to use with this instance
   * @param handler
   *            the callback handler for this instance
   * @throws ToxException
   *             when the native call indicates an error
   */
  public JTox(FriendList<F> friendList, CallbackHandler<F> handler, ToxOptions toxOptions) throws ToxException {
    this.friendList = friendList;
    this.handler = handler;
    long pointer = tox_new(toxOptions);

    if (pointer == 0) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }

    this.messengerPointer = pointer;
    long avPointer = toxav_new(this.messengerPointer, 16);

    if (avPointer == 0) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }

    this.avPointer = avPointer;
    this.lock = new ReentrantLock();
    validPointers.add(pointer);
    validPointers.add(avPointer);
    instanceLock.lock();

    try {
      this.instanceNumber = instanceCounter++;
      instances.put(instanceCounter, this);
    } finally {
      instanceLock.unlock();
    }
  }

  /**
   * Creates a new instance of JTox and stores the pointer to the internal
   * struct in messengerPointer. Also attempts to load the specified byte
   * array into this instance.
   *
   * @param data
   *            the data to load for the new tox instance
   * @param friendList
   *            friend list to use with this tox instance
   * @param handler
   *            callback handler to use with this instance
   * @throws ToxException
   *             when the native call indicates an error
   */
  public JTox(byte[] data, FriendList<F> friendList, CallbackHandler<F> handler, ToxOptions toxOptions) throws ToxException {
    this(friendList, handler, toxOptions);
    this.load(data);
  }

  /**
   * Native call to tox_get_address
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct.
   *
   * @return the client's address on success, null on failure
   */
  private native String tox_get_address(long messengerPointer);

  /**
   * Get our own address
   *
   * @return our client's address
   * @throws ToxException
   *             when the instance has been killed or an error occurred when
   *             trying to get our address
   */
  public String getAddress() throws ToxException {
    String address;

    this.lock.lock();

    try {
      checkPointer();
      address = tox_get_address(this.messengerPointer);
    } finally {
      this.lock.unlock();
    }

    if (address == null || address.equals("")) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }

    return address;
  }

  /**
   * Native call to tox_get_self_user_status
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @return our current status
   * @throws ToxException
   *             if the instance has been killed
   */
  private native ToxUserStatus tox_get_self_user_status(long messengerPointer);

  /**
   * Get our own current status
   *
   * @return one of {@link ToxUserStatus}
   * @throws ToxException
   */
  public ToxUserStatus getSelfUserStatus() throws ToxException {
    this.lock.lock();

    try {
      checkPointer();

      return tox_get_self_user_status(this.messengerPointer);
    } finally {
      this.lock.unlock();
    }
  }

  /**
   * Native call to tox_set_status_message
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param message
   *            our new status message
   * @param length
   *            the length of the new status message in bytes
   * @return false on success, true on failure
   */
  private native boolean tox_set_status_message(long messengerPointer, byte[] message, int length);

  /**
   * Sets our status message
   *
   * @param message
   *            our new status message
   * @throws ToxException
   *             if the instance has been killed, the message was too long, or
   *             another error occurred
   */
  public void setStatusMessage(String message) throws ToxException {
    byte[] messageArray = getStringBytes(message);

    if (messageArray.length >= TOX_MAX_STATUSMESSAGE_LENGTH) {
      throw new ToxException(ToxError.TOX_TOOLONG);
    }

    boolean error;

    this.lock.lock();

    try {
      checkPointer();

      error = tox_set_status_message(this.messengerPointer, messageArray, messageArray.length);
    } finally {
      this.lock.unlock();
    }

    if (error) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }
  }

  /**
   * Native call to tox_get_self_name
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @return our name
   */
  private native String tox_get_self_name(long messengerPointer);

  /**
   * Function to get our current name
   *
   * @return our name
   * @throws ToxException
   *             if the instance has been killed
   */
  public String getSelfName() throws ToxException {
    this.lock.lock();
    String name;

    try {
      checkPointer();

      name = tox_get_self_name(this.messengerPointer);
    } finally {
      this.lock.unlock();
    }

    if (name == null) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }

    return name;
  }

  /**
   * Native call to tox_set_name
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param newname
   *            the new name
   * @param length
   *            length of the new name in byte
   * @return false on success, true on failure
   */
  private native boolean tox_set_name(long messengerPointer, byte[] newname, int length);

  /**
   * Sets our nickname
   *
   * @param newname
   *            the new name to set. Maximum length is 128 bytes. This means
   *            that a name containing UTF-8 characters has a shorter
   *            character limit than one only using ASCII.
   * @throws ToxException
   *             if the instance was killed, the name was too long, or another
   *             error occurred
   */
  public void setName(String newname) throws ToxException {
    byte[] newnameArray = getStringBytes(newname);

    if (newnameArray.length >= TOX_MAX_NICKNAME_LENGTH) {
      throw new ToxException(ToxError.TOX_TOOLONG);
    }

    boolean error;

    this.lock.lock();

    try {
      checkPointer();

      error = tox_set_name(this.messengerPointer, newnameArray, newnameArray.length);
    } finally {
      this.lock.unlock();
    }

    if (error) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }
  }

  /**
   * Native call to tox_set_user_status
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param status
   *            status to set
   * @return false on success, true on failure
   */
  private native boolean tox_set_user_status(long messengerPointer, int status);

  /**
   * Set our current {@link ToxUserStatus}.
   *
   * @param status
   *            the status to set
   * @throws ToxException
   *             if the instance was killed, we tried to set our status to
   *             invalid, or an error occurred while setting status
   */
  public void setUserStatus(ToxUserStatus status) throws ToxException {
    if (status == ToxUserStatus.TOX_USERSTATUS_INVALID) {
      throw new ToxException(ToxError.TOX_STATUS_INVALID);
    }

    boolean error;

    this.lock.lock();

    try {
      checkPointer();

      error = tox_set_user_status(this.messengerPointer, status.ordinal());
    } finally {
      this.lock.unlock();
    }

    if (error) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }
  }

  /**
   * Native call to tox_add_friend
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param address
   *            address of the friend
   * @param data
   *            optional message sent to friend
   * @param length
   *            length of the message sent to friend
   * @return friend number on success, error code on failure
   */
  private native int tox_add_friend(long messengerPointer, byte[] address, byte[] data, int length);

  /**
   * Method used to add a friend. On success, the friend is added to the list
   * of friends, and a reference to the friend is returned.
   *
   * @param address
   *            the address of the friend you want to add
   * @param data
   *            an optional message you want to send to your friend
   * @return the friend
   * @throws ToxException
   *             if the instance has been killed or an error code is returned
   *             by the native tox_addfriend call
   * @throws FriendExistsException
   *             if the friend already exists
   */
  public F addFriend(String address, String data) throws ToxException, FriendExistsException {
    byte[] dataArray = getStringBytes(data);
    byte[] addressArray = hexToByteArray(address);
    int errcode;
    this.lock.lock();

    try {
      checkPointer();
      errcode = tox_add_friend(this.messengerPointer, addressArray, dataArray, dataArray.length);
    } finally {
      this.lock.unlock();
    }

    return getFriendOrFail(address, errcode);
  }

  /**
   * Native call to tox_add_friend_norequest
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param address
   *            the address of the client you want to add
   * @return the local number of the friend in your list
   */
  private native int tox_add_friend_norequest(long messengerPointer, byte[] address);

  /**
   * Confirm a friend request, or add a friend to your own list without
   * sending them a friend request. If successful, the Friend is added to the
   * list, and a reference to the friend is returned.
   *
   * @param address
   *            address of the friend to add
   * @return the friend
   * @throws ToxException
   *             if the instance was killed or an error occurred when adding
   *             the friend
   * @throws FriendExistsException
   *             if the friend already exists
   */
  public F confirmRequest(String address) throws ToxException, FriendExistsException {
    byte[] addressArray = hexToByteArray(address);
    int errcode;
    this.lock.lock();

    try {
      checkPointer();

      errcode = tox_add_friend_norequest(this.messengerPointer, addressArray);
    } finally {
      this.lock.unlock();
    }

    return getFriendOrFail(address, errcode);
  }

  private F getFriendOrFail(String address, int errcode) throws FriendExistsException, ToxException {
    if (errcode >= 0) {
      F friend = this.friendList.addFriend(errcode);
      friend.setId(address);
      return friend;
    }

    throw new ToxException(errcode);
  }

  /**
   * Native call to tox_del_friend
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param friendnumber
   *            the number of the friend
   * @return false on success, true on failure
   */
  private native boolean tox_del_friend(long messengerPointer, int friendnumber);

  /**
   * Method used to delete a friend
   *
   * @param friendnumber
   *            the friend to delete
   * @throws ToxException
   *             if the instance has been killed or an error occurred
   */
  public void deleteFriend(int friendnumber) throws ToxException {
    boolean error;
    this.lock.lock();

    try {
      checkPointer();

      error = tox_del_friend(this.messengerPointer, friendnumber);
    } finally {
      this.lock.unlock();
    }

    if (error) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }

    this.friendList.removeFriend(friendnumber);
  }

  /**
   * Native call to tox_send_message
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param friendnumber
   *            the number of the friend
   * @param message
   *            the message
   * @param length
   *            length of the message in bytes
   * @return the message ID on success, 0 on failure
   */
  private native int tox_send_message(long messengerPointer, int friendnumber, byte[] message, int length);

  /**
   * Sends a message to the specified friend. Add the message ID of the sent
   * message to the list of sent messages of the receiving friend.
   *
   * @param friend
   *            the friend
   * @param message
   *            the message
   * @return the message ID of the sent message. This is stored in the Friend's list of sent
     *            messages. This value is also passed to the read receipt callback if the message
     *            was received and should be compared to your list of stored values.
   * @throws ToxException
   *             if the instance has been killed or the message was not sent
   */
  public int sendMessage(F friend, String message) throws ToxException {
    byte[] messageArray = getStringBytes(message);
    int result;

    this.lock.lock();

    try {
      checkPointer();

      result = tox_send_message(this.messengerPointer, friend.getFriendnumber(), messageArray,
                    messageArray.length);
    } finally {
      this.lock.unlock();
    }

    if (result == 0) {
      throw new ToxException(ToxError.TOX_SEND_FAILED);
    }

    return result;
  }

  /**
   * Native call to tox_send_action
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param friendnumber
   *            the number of the friend
   * @param action
   *            the action to send
   * @param length
   *            length of the action in bytes
   * @return false on success, true on failure
   */
  private native boolean tox_send_action(long messengerPointer, int friendnumber, byte[] action, int length);

  /**
   * Sends an IRC-like /me-action to a friend
   *
   * @param friend
   *            the friend
   * @param action
   *            the action
   * @throws ToxException
   *             if the instance has been killed or the send failed
   */
  public void sendAction(F friend, String action) throws ToxException {
    byte[] actionArray = getStringBytes(action);
    boolean error;

    this.lock.lock();

    try {
      checkPointer();

      error = tox_send_action(this.messengerPointer, friend.getFriendnumber(), actionArray, actionArray.length);
    } finally {
      this.lock.unlock();
    }

    if (error) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }
  }

  /**
   * Native call to tox_set_user_is_typing
   * @param messengerPointer pointer to the internal messenger struct
   * @param friendnumber the friend's number
   * @param typing <code>true</code> indicates we are typing, <code>false</code> indicates we stopped typing
   * @return false on success, true on failure
   */
  private native boolean tox_set_user_is_typing(long messengerPointer, int friendnumber, boolean typing);

  /**
   * Indicate to the specified friend that we are currently typing
   * @param friendnumber the friend's number
   * @param typing <code>true</code> indicates we are typing, <code>false</code> indicates we stopped typing
   * @throws ToxException if the instance has been killed
   */
  public void sendIsTyping(int friendnumber, boolean typing) throws ToxException {
    boolean error;

    this.lock.lock();

    try {
      checkPointer();

      error = tox_set_user_is_typing(this.messengerPointer, friendnumber, typing);
    } finally {
      this.lock.unlock();
    }

    if (error) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }
  }

  /**
   * Native call to tox_do
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   */
  private native void tox_do(long messengerPointer);

  /**
   * The main tox loop that needs to be run at least 20 times per second. When
   * implementing this, either use it in a main loop to guarantee execution,
   * or start an asynchronous Thread or Service to do it for you.
   *
   * @throws ToxException
   *             if the instance has been killed
   */
  public void doTox() throws ToxException {
    this.lock.lock();

    try {
      checkPointer();

      tox_do(this.messengerPointer);
    } finally {
      this.lock.unlock();
    }
  }

  private native int tox_do_interval(long messengerPointer);

  /**
   * Return the time in milliseconds before doTox() should be called again
   * for optimal performance.
   * @return time in ms, -1 on failure
   * @throws ToxException
   */
  public int doToxInterval() throws ToxException {
    this.lock.lock();
    int result = -1;

    try {
      checkPointer();

      result = tox_do_interval(this.messengerPointer);
    } finally {
      this.lock.unlock();
    }

    return result;
  }
  /**
   * Native call to tox_bootstrap_from_address
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param ip
   *            ip address to bootstrap with
   * @param port
   *            port to bootstrap with
   * @param pubkey
   *            public key of the bootstrap node
   */
  private native int tox_bootstrap_from_address(long messengerPointer, String ip, int port, byte[] pubkey);

  /**
   * Method used to bootstrap the client's connection.
   *
   * @param host
   *            Hostname or IP(v4, v6) address to connect to. If the hostname
   *            contains non-ASCII characters, convert it to punycode when
   *            calling this method.
   * @param port
   *            port to connect to
   * @param pubkey
   *            public key of the bootstrap node
   * @throws ToxException
   *             if the instance has been killed or an invalid port was
   *             specified
   * @throws UnknownHostException
   *             if the host could not be resolved or the IP address was
   *             invalid
   */
  public void bootstrap(String host, int port, String pubkey) throws ToxException, UnknownHostException {
    byte[] pubkeyArray = hexToByteArray(pubkey);
    boolean error;

    if (port < 0 || port > 65535) {
      throw new ToxException(ToxError.TOX_INVALID_PORT);
    }

    this.lock.lock();

    try {
      checkPointer();

      error = tox_bootstrap_from_address(this.messengerPointer, host, port, pubkeyArray) == 0;
    } finally {
      this.lock.unlock();
    }

    if (error) {
      throw new UnknownHostException(host);
    }
  }

  /**
   * Native call to tox_isconnected
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   */
  private native int tox_isconnected(long messengerPointer);

  /**
   * Check if the client is connected to the DHT
   *
   * @return true if connected, false otherwise
   * @throws ToxException
   *             if the instance has been killed
   */
  public boolean isConnected() throws ToxException {
    this.lock.lock();

    try {
      checkPointer();

      return tox_isconnected(this.messengerPointer) != 0;
    } finally {
      this.lock.unlock();
    }
  }

  /**
   * Native call to tox_kill
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   */
  private native void tox_kill(long messengerPointer);

  /**
   * Kills the current instance, triggering a cleanup of all internal data
   * structures. All subsequent calls on any method in this class will result
   * in a {@link ToxException} with {@link ToxError#TOX_KILLED_INSTANCE} as an
   * error code.
   *
   * @throws ToxException
   *             in case the instance has already been killed
   */
  public void killTox() throws ToxException {
    this.lock.lock();

    try {
      checkPointer();

      validPointers.remove(this.messengerPointer);
      tox_kill(this.messengerPointer);

      checkAvPointer();
      validPointers.remove(this.avPointer);
      toxav_kill(this.avPointer);
    } finally {
      this.lock.unlock();
    }

    instances.remove(this.instanceNumber);
  }

  /**
   * Native call to tox_save
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @return a byte array containing the saved data
   */
  private native byte[] tox_save(long messengerPointer);

  /**
   * Save the internal messenger data to a byte array, which can be saved to a
   * file or database
   *
   * @return a byte array containing the saved data
   * @throws ToxException
   *             if the instance has been killed
   */
  public byte[] save() throws ToxException {
    this.lock.lock();

    try {
      checkPointer();

      return tox_save(this.messengerPointer);
    } finally {
      this.lock.unlock();
    }
  }

  /**
   * Native call to tox_load
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param data
   *            a byte array containing the data to load
   * @param length
   *            the length of the byte array
   * @return false on success, true on failure
   */
  private native boolean tox_load(long messengerPointer, byte[] data, int length);

  /**
   * Load the specified data into this tox instance.
   *
   * @param data
   *            a byte array containing the data to load
   * @throws ToxException
   *             if the instance has been killed, or an error occurred while
   *             loading
   */
  private void load(byte[] data) throws ToxException {
    boolean error;

    this.lock.lock();

    try {
      checkPointer();

      error = tox_load(this.messengerPointer, data, data.length);
      refreshList();
    } finally {
      this.lock.unlock();
    }

    if (error) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }
  }

  /**
   * Refresh the friend list, looking for new friends, status changes, name
   * changes etc. Generally, the core should keep this
   *
   * @throws ToxException
   *             if the instance was killed, or an internal error occured
   */
  public void refreshList() throws ToxException {
    for (int i : getInternalFriendList()) {
      this.friendList.addFriendIfNotExists(i);
      refreshClientId(i);
      refreshFriendName(i);
      refreshStatusMessage(i);
      refreshUserStatus(i);
      refreshFriendConnectionStatus(i);
    }
  }

  /**
   * Native call to tox_get_friendlist
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @return array containing valid friend numbers
   */
  private native int[] tox_get_friendlist(long messengerPointer);

  /**
   * Get a list of all currently valid friend numbers.
   *
   * @return ArrayList containing the
   * @throws ToxException
   *             if the instance was killed, or the list was not retrieved
   */
  private int[] getInternalFriendList() throws ToxException {
    int[] ids;

    this.lock.lock();

    try {
      checkPointer();

      ids = tox_get_friendlist(this.messengerPointer);
    } finally {
      this.lock.unlock();
    }

    if (ids == null) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }

    return ids;
  }

  /**
   * Native call to tox_get_client_id
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param friendnumber
   *            local number of the friend
   * @return the public key of the specified friend
   */
  private native String tox_get_client_id(long messengerPointer, int friendnumber);

  /**
   * Refresh the client ID for a given friend.
   *
   * @param friendnumber
   *            the friendnumber
   * @throws ToxException
   *             if the instance has been killed, or an error occurred when
   *             attempting to fetch the client id
   */
  public void refreshClientId(int friendnumber) throws ToxException {
    String result;
    this.lock.lock();

    try {
      checkPointer();

      result = tox_get_client_id(this.messengerPointer, friendnumber);
    } finally {
      this.lock.unlock();
    }

    if (result == null || result.equals("")) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }

    this.friendList.getByFriendNumber(friendnumber).setId(result);
  }

  /**
   * Native call to tox_get_friend_connection_status
   *
   * @param friendnumber
   *            the friend's number
   * @return connecting status of a friend
   */
  private native int tox_get_friend_connection_status(long messengerPointer, int friendnumber);

  /**
   * Refresh the connection status for a given friend
   *
   * @param friendnumber
   *            the friendnumber
   * @throws ToxException
   *             if the instance has been killed, or an error occurred when
   *             attempting to fetch the connection status
   */
  public void refreshFriendConnectionStatus(int friendnumber) throws ToxException {
    this.lock.lock();
    int result;

    try {
      checkPointer();
      result = tox_get_friend_connection_status(this.messengerPointer, friendnumber);
    } finally {
      this.lock.unlock();
    }

    if (result == -1) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }

    F friend = this.friendList.getByFriendNumber(friendnumber);

    if (result == 0) {
      friend.setOnline(false);
    } else {
      friend.setOnline(true);
    }
  }

  /**
   * Checks if there exists a friend with given friendnumber.
   *
   * @param friendnumber
   *            the friendnumber
   * @throws ToxException
   *             if the instance has been killed, or an error occurred when
   *             attempting to fetch the connection status
   */
  private native boolean tox_get_friend_exists(long messengerPointer, int friendnumber);

  /**
   * Check whether a friend with the given friendnumber exists
   *
   * @param friendnumber
   *            the friendnumber
   */
  public boolean toxFriendExists(int friendnumber) throws ToxException {
    boolean exists;

    this.lock.lock();

    try {
      checkPointer();
      exists = tox_get_friend_exists(this.messengerPointer, friendnumber);
    } finally {
      this.lock.unlock();
    }

    return exists;
  }

  /**
   * Native call to tox_get_name
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param friendnumber
   *            the friend's number
   * @return the specified friend's name
   */
  private native byte[] tox_get_name(long messengerPointer, int friendnumber);

  /**
   * Refresh the specified friend's name
   *
   * @param friendnumber
   *            the friend's number
   * @throws ToxException
   *             if the instance has been killed or an error occurred
   */
  public void refreshFriendName(int friendnumber) throws ToxException {
    byte[] name;

    this.lock.lock();

    try {
      checkPointer();

      name = tox_get_name(this.messengerPointer, friendnumber);
    } finally {
      this.lock.unlock();
    }

    if (name == null) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }

    this.friendList.getByFriendNumber(friendnumber).setName(getByteString(name));
  }

  /**
   * Native call to tox_get_status_message
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param friendnumber
   *            the friend's number
   * @return the status message
   */
  private native byte[] tox_get_status_message(long messengerPointer, int friendnumber);

  /**
   * Refresh the friend's status message.
   *
   * @param friendnumber
   *            the friend's number
   * @throws ToxException
   *             if the instance has been killed, or an error occurred while
   *             getting the status message
   */
  public void refreshStatusMessage(int friendnumber) throws ToxException {
    byte[] status;

    this.lock.lock();

    try {
      checkPointer();

      status = tox_get_status_message(this.messengerPointer, friendnumber);
    } finally {
      this.lock.unlock();
    }

    if (status == null) {
      throw new ToxException(ToxError.TOX_UNKNOWN);
    }

    this.friendList.getByFriendNumber(friendnumber).setStatusMessage(getByteString(status));
  }

  /**
   * Native call to tox_get_userstatus
   *
   * @param messengerPointer
   *            pointer to the internal messenger struct
   * @param friendnumber
   *            the friend's number
   * @return the friend's status
   */
  private native ToxUserStatus tox_get_user_status(long messengerPointer, int friendnumber);

  /**
   * Refresh status for the specified friend
   *
   * @param friendnumber
   *            the friend's number
   * @throws ToxException
   *             if the instance has been killed
   */
  public void refreshUserStatus(int friendnumber) throws ToxException {
    ToxUserStatus status = ToxUserStatus.TOX_USERSTATUS_INVALID;

    this.lock.lock();

    try {
      checkPointer();

      status = tox_get_user_status(this.messengerPointer, friendnumber);
    } finally {
      this.lock.unlock();
    }

    this.friendList.getByFriendNumber(friendnumber).setStatus(status);
  }

  /**
   * Native call to tox_get_is_typing
   * @param messengerPointer pointer to the internal messenger struct
   * @param friendnumber the friend's number
   * @return <code>true</code> if the friend is typing, <code>false</code> otherwise
   */
  private native boolean tox_get_is_typing(long messengerPointer, int friendnumber);

  /**
   * Refresh the typing status for the specified friend
   * @param friendnumber the friend's number
   * @throws ToxException if the instance has been killed
   */
  public void refreshTypingStatus(int friendnumber) throws ToxException {
    boolean result;
    this.lock.lock();

    try {
      checkPointer();

      result = tox_get_is_typing(this.messengerPointer, friendnumber);
    } finally {
      this.lock.unlock();
    }

    this.friendList.getByFriendNumber(friendnumber).setTyping(result);
  }

  /****** GROUP CHAT FUNCTIONS ******/

  /**
   * Creates a new groupchat and puts it in the chats array.
   * @param messengerPointer pointer to the internal messenger struct
   * @return group number on success, -1 on failure
   *
  private native int tox_add_groupchat(long messengerPointer);

  /**
   * Delete a groupchat from the chats array.
   * @param messengerPointer pointer to the internal messenger struct
   * @param groupnumber group to delete
   * @return false on success, true on failure
   *
  private native boolean tox_del_groupchat(long messengerPointer, int groupnumber);

  /**
   * Return the name of peernumber who is in groupnumber
   * @param messengerPointer pointer to the internal messenger struct
   * @param groupnumber
   * @param peernumber
   * @return the name of the peer as a byte array
   *
  private native byte[] tox_group_peername(long messengerPointer, int groupnumber, int peernumber);

  /**
   * Invite friendnumber to groupnumber
   * @param messengerPointer pointer to the internal messenger struct
   * @param friendnumber
   * @param groupnumber
   * @return false on success, true on failure
   *
  private native boolean tox_invite_friend(long messengerPointer, int friendnumber, int groupnumber);

  /**
   * Join a group (you need to have been invited first.)
   * @param messengerPointer pointer to the internal messenger struct
   * @param friendnumber
   * @param friend_group_public_key
   * @return group number on success, -1 on failure
   *
  private native int tox_join_groupchat(long messengerPointer, int friendnumber,
                                        byte[] friend_group_public_key);

  /**
   * Sends a group message
   * @param messengerPointer pointer to the internal messenger struct
   * @param groupnumber
   * @param message
   * @param length
   * @return false on success, true on failure
   *
  private native boolean tox_group_message_send(long messengerPointer, int groupnumber,
                                                byte[] message, int length);

  /**
   * Send a group action
   * @param messengerPointer
   * @param groupnumber
   * @param action
   * @param length
   * @return false on success, true on failure
   *
  private native boolean tox_group_action_send(long messengerPointer, int groupnumber,
                                           byte[] action, int length);

  /**
   * Return the number of peers in the group chat on success.
   * @param messengerPointer
   * @param groupnumber
   * @return the number of peers in the group chat on success, -1 on failure
   *
  private native int tox_group_number_peers(long messengerPointer, int groupnumber);

  *
  private native byte[][] tox_group_get_names(long messengerPointer, int groupnumber);

  public byte[][] toxGroupGetNames(int groupnumber) throws ToxException {
      byte[][] result;
      this.lock.lock();
      try {
          checkPointer();
          result = tox_group_get_names(this.messengerPointer, groupnumber);
      } finally {
          this.lock.unlock();
      }
      return result;
  }
  */

  /****** GROUP CHAT FUNCTIONS END ******/

  private native int tox_get_nospam(long messengerPointer);

  /**
   * Get your nospam
   * @return nospam
   * @throws ToxException
   */
  public int getNospam() throws ToxException {
    int result;
    this.lock.lock();

    try {
      checkPointer();
      result = tox_get_nospam(this.messengerPointer);
    } finally {
      this.lock.unlock();
    }

    return result;
  }

  private native void tox_set_nospam(long messengerPointer, int nospam);

  /**
   * Set your no spam
   * @param nospam
   * @throws ToxException
   */
  public void setNospam(int nospam) throws ToxException {
    this.lock.lock();

    try {
      checkPointer();
      tox_set_nospam(this.messengerPointer, nospam);
    } finally {
      this.lock.unlock();
    }
  }

  /****** FILE SENDING FUNCTIONS BEGIN ******/
  private native int tox_new_file_sender(long messengerPointer, int friendnumber, long filesize, byte[] filename,
                       int length);

  /**
   * Send a file send request.
   * Maximum filename length is 255 bytes
   * @param friendnumber
   * @param filesize
   * @param filename
   * @return filenumber on success, -1 on failure
   * @throws ToxException
   */
  public int newFileSender(int friendnumber, long filesize, String filename) throws ToxException {
    int result;
    byte[] _filename = filename.getBytes(Charset.forName("UTF-8"));
    this.lock.lock();

    try {
      checkPointer();
      result = tox_new_file_sender(this.messengerPointer, friendnumber, filesize, _filename, _filename.length);
    } finally {
      this.lock.unlock();
    }

    return result;
  }

  private native int tox_file_send_control(long messengerPointer, int friendnumber, int send_receive, int filenumber,
      int message_id, byte[] data, int length);

  /**
   * Send a file control request.
   * sending is true if we want the control packet to target a file we are currently sending,
   * false if it targets a file we are currently receiving.
   * @param friendnumber
   * @param sending
   * @param filenumber
   * @param message_id
   * @param data
   * @return 0 on success, -1 on failure
   * @throws ToxException
   */
  public int fileSendControl(int friendnumber, boolean sending, int filenumber, int message_id,
                 byte[] data) throws ToxException {
    int result;
    int send_receive;

    if (sending) {
      send_receive = 0;
    } else {
      send_receive = 1;
    }

    this.lock.lock();

    try {
      checkPointer();
      result = tox_file_send_control(this.messengerPointer, friendnumber, send_receive, filenumber, message_id, data,
                       data.length);
    } finally {
      this.lock.unlock();
    }

    return result;
  }

  private native int tox_file_send_data(long messengerPointer, int friendnumber, int filenumber, byte[] data, int length);

  /**
   * Send file data
   * @param friendnumber
   * @param filenumber
   * @param data
   * @return 0 on success, -1 on failure
   * @throws ToxException
   */
  public int fileSendData(int friendnumber, int filenumber, byte[] data) throws ToxException {
    int result;
    this.lock.lock();

    try {
      checkPointer();
      result = tox_file_send_data(this.messengerPointer, friendnumber, filenumber, data, data.length);
    } finally {
      this.lock.unlock();
    }

    return result;
  }

  private native int tox_file_data_size(long messengerPointer, int friendnumber);

  /**
   * Give the number of bytes left to be sent/received.
   * @param friendnumber
   * @return size in bytes on success, -1 on failure
   * @throws ToxException
   */
  public int fileDataSize(int friendnumber) throws ToxException {
    int result;
    this.lock.lock();

    try {
      checkPointer();
      result = tox_file_data_size(this.messengerPointer, friendnumber);
    } finally {
      this.lock.unlock();
    }

    return result;
  }

  private native long tox_file_data_remaining(long messengerPointer, int friendnumber, int filenumber, int send_receive);

  /**
   * Give the number of bytes left to be sent/received.
   * sending is true if we want a file we are sending, false if we want one we are receiving
   * @param friendnumber
   * @param filenumber
   * @param sending
   * @return number of bytes left on success, 0 on failure
   * @throws ToxException
   */
  public long fileDataRemaining(int friendnumber, int filenumber, boolean sending) throws ToxException {
    long result;
    int send_receive;

    if (sending) {
      send_receive = 0;
    } else {
      send_receive = 1;
    }

    this.lock.lock();

    try {
      checkPointer();
      result = tox_file_data_remaining(this.messengerPointer, friendnumber, filenumber, send_receive);
    } finally {
      this.lock.unlock();
    }

    return result;
  }
  /****** FILE SENDING FUNCTIONS END ******/


  /**
   * Utility method that checks the current pointer and throws an exception if
   * it is not valid
   *
   * @throws ToxException
   *             if the instance has been killed
   */
  private void checkPointer() throws ToxException {
    if (!validPointers.contains(this.messengerPointer)) {
      throw new ToxException(ToxError.TOX_KILLED_INSTANCE);
    }
  }

  private void checkAvPointer() throws ToxException {
    if (!validPointers.contains(this.avPointer)) {
      throw new ToxException(ToxError.TOX_KILLED_INSTANCE);
    }
  }
  /**
   * If you need to pass a JTox instance around between different contexts,
   * and are unable to pass instances directly, use this method to acquire the
   * instance number of this instance. Once acquired, you can acquire the
   * instance with {@link JTox#getInstance(int)}.
   *
   * @return the instance number
   */
  public int getInstanceNumber() {
    return this.instanceNumber;
  }

  /**
   * @return the friendlist
   */
  public FriendList<F> getFriendList() {
    return this.friendList;
  }

  /**
   * Get the instance associated with the specified instance number. This may
   * return <code>null</code> if either the instance was killed, or if no
   * instance with that number exists.
   *
   * @param instancenumber
   * @return the associated instance
   */
  public static JTox<?> getInstance(int instancenumber) {
    return instances.get(instancenumber);
  }

  /**
   * Turns the given String into an array of UTF-8 encoded bytes
   *
   * @param in
   *            the String to convert
   * @return a byte array
   */
  public static byte[] getStringBytes(String in) {
    return (in).getBytes(Charset.forName("UTF-8"));
  }

  /**
   * Turns the given byte array into a UTF-8 encoded string
   *
   * @param in
   *            the byte array to convert
   * @return an UTF-8 String based on the given byte array
   */
  public static String getByteString(byte[] in) {
      return new String(in, Charset.forName("UTF-8"));
  }

  /**
   * Convert a given hexadecimal String to a byte array.
   *
   * @param in
   *            String to convert
   * @return byte array representation of the hexadecimal String
   */
  public static byte[] hexToByteArray(String in) {
    int length = in.length();
    byte[] out = new byte[length / 2];

    for (int i = 0; i < length; i += 2) {
      out[i / 2] = (byte) ((Character.digit(in.charAt(i), 16) << 4) + Character.digit(in.charAt(i + 1), 16));
    }

    return out;
  }
  ///////////////////////AUDIO / VIDEO///////////////////////////////////////////////
  /**
   * Native call to toxav_new
   * Start new a/v session, There can only be one session at the time. If you register more
   * it will result in undefined behaviour.
   *
   * @param messengerPointer messenger pointer
   * @param max_calls max number of calls
   * @return the pointer to the av session struct on success, null on failure
   */
  private native long toxav_new(long messengerPointer, int max_calls);

  /**
  * Remove A/V session.
  *
  * @param avPointer av handler pointer
  * @return void
  */
  private native void toxav_kill(long avPointer);

  /**
  * Call user. Use its friend_id.
  *
  * @param av Handler.
  * @param call_index Call index
  * @param user The user.
  * @param csettings Codec settings
  * @param ringing_seconds Ringing timeout.
  * @return int, 0 on success
  */
  private native int toxav_call(long avPointer, int user, ToxCodecSettings csettings, int ringing_seconds);

  /**
   * Call user using friend_id
   * @param user friend_id of the user
   * @param csettings codec settings
   * @param ringingSeconds seconds to ring
   * @return 0 on success, otherwise error value
   * @throws ToxException
   */
  public int avCall(int user, ToxCodecSettings csettings, int ringingSeconds) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_call(this.avPointer, user, csettings, ringingSeconds);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Hangup active call.
  *
  * @param av Handler.
  * @return 0 on success
  */
  private native int toxav_hangup(long avPointer, int call_index);

  /**
   * Hangup active call
   * @param callIndex
   * @return 0 on success
   * @throws ToxException
   */
  public int avHangup(int callIndex) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_hangup(this.avPointer, callIndex);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Answer incoming call.
  *
  * @param av Handler.
  * @param call_index call index
    * @param csettings codec settings
  * @return 0 on success
  */
  private native int toxav_answer(long avPointer, int call_index, ToxCodecSettings csettings );

  /**
   * Answer incoming call
   * @param callIndex call index
   * @param csettings codec settings
   * @return 0 on success
   * @throws ToxException
   */
  public int avAnswer(int callIndex, ToxCodecSettings csettings) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_answer(this.avPointer, callIndex, csettings);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Reject incomming call.
  *
  * @param av Handler.
    * @param call_index call index
  * @param reason Optional reason. Set NULL if none.
  * @return int
  */
  private native int toxav_reject(long avPointer, int call_index, String reason);

  /**
   * Reject incoming call
   * @param callIndex
   * @param reason
   * @return 0 on success
   * @throws ToxException
   */
  public int avReject(int callIndex, String reason) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_reject(this.avPointer, callIndex, reason);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Cancel outgoing request.
  *
  * @param av Handler.
    * @param call_index call index
  * @param reason Optional reason.
  * @param peer_id peer friend_id
  * @return 0 on success
  */
  private native int toxav_cancel(long avPointer, int call_index, int peer_id, String reason);

  /**
    * Cancel outgoing request
    * @param callIndex
    * @param peerId
    * @param reason
    * @return 0 on success
    * @throws ToxException
    */
  public int avCancel(int callIndex, int peerId, String reason) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_cancel(this.avPointer, callIndex, peerId, reason);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Notify peer that we are changing call settings
  *
  * @param av Handler.
    * @param call_index call index
    * @param csettings codec settings
  * @return 0 on success
  */
  private native int toxav_change_settings(long avPointer, int call_index, ToxCodecSettings csettings);

  /**
   * Change call settings
   * @param callIndex
   * @param csettings
   * @return 0 on success
   * @throws ToxException
   */
  public int avChangeSettings(int callIndex, ToxCodecSettings csettings) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_change_settings(this.avPointer, callIndex, csettings);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Terminate transmission. Note that transmission will be terminated without informing remote peer.
  *
  * @param av Handler.
    * @param call_index call index
  * @return 0 on success
  */
  private native int toxav_stop_call(long avPointer, int call_index);

  /**
   * Terminate transmission, without informing remote peer.
   * @param callIndex
   * @return 0 on success
   * @throws ToxException
   */
  public int avStopCall(int callIndex) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_stop_call(this.avPointer, callIndex);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Must be call before any RTP transmission occurs.
  *
  * @param av Handler.
    * @param call_index call index
    * @param jbuf_size buffer size
    * @param VAD_treshold VAD threshold
  * @param support_video Is video supported ? 1 : 0
  * @return 0 on success
  */
  private native int toxav_prepare_transmission(long avPointer, int call_index, int jbuf_size,
      int VAD_treshold, int support_video);

  /**
   * Prepare call for RTP transmission
   * @param callIndex
   * @param jBufSize
   * @param VADThreshold
   * @param supportVideo
   * @return 0 on success
   * @throws ToxException
   */
  public int avPrepareTransmission(int callIndex, int jBufSize, int VADThreshold, boolean supportVideo) throws ToxException {
    this.lock.lock();
    int ret;
    int s;

    if (supportVideo) {
      s = 1;
    } else {
      s = 0;
    }

    try {
      checkPointer();
      ret = toxav_prepare_transmission(this.avPointer, callIndex, jBufSize, VADThreshold, s);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Call this at the end of the transmission.
  *
  * @param av Handler.
    * @param call_index call index
  * @return 0 on success
  */
  private native int toxav_kill_transmission(long avPointer, int call_index);

  /**
   * Call this at the end of the transmission
   * @param callIndex
   * @return 0 on success
   * @throws ToxException
   */
  public int avKillTransmission(int callIndex) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_kill_transmission(this.avPointer, callIndex);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Encode and send video packet.
  *
  * @param av Handler.
    * @param call_index call index
  * @param frame The encoded frame.
  * @param frame_size The size of the encoded frame.
  * @return 0 on success
  */
  private native int toxav_send_video (long avPointer, int call_index, byte[] frame, int frame_size);

  /**
   * Send video frame
   * @param callIndex
   * @param frame
   * @return 0 on success
   * @throws ToxException
   */
  public int avSendVideo(int callIndex, byte[] frame) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_send_video(this.avPointer, callIndex, frame, frame.length);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Send audio frame.
  *
  * @param av Handler.
    * @param call_index call index
  * @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.)
  * @param frame_size Its size in number of frames/samples (one frame/sample is 16 bits or 2 bytes)
  * frame size should be AUDIO_FRAME_SIZE.
  * @return 0 on success
  */
  private native int toxav_send_audio (long avPointer, int call_index, byte[] frame, int frame_size);

  /**
   * Send audio frame
   * @param callIndex
   * @param frame
   * @return 0 on success
   * @throws ToxException
   */
  public int avSendAudio(int callIndex, byte[] frame) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_send_audio(this.avPointer, callIndex, frame, frame.length);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Encode video frame
  *
  * @param av Handler
    * @param call_index call index
  * @param dest_max Max size
  * @param data What to encode
    * @param width width
    * @param height height
  * @return byte array on success, null on fail
  */
  private native byte[] toxav_prepare_video_frame (long avPointer, int call_index, int dest_max, byte[] data, int width, int height);

  /**
   * Encode video frame
   * @param callIndex
   * @param destMax
   * @param data
   * @param width
   * @param height
   * @return The encoded video frame
   * @throws ToxException
   */
  public byte[] avPrepareVideoFrame(int callIndex, int destMax, byte[] data, int width, int height) throws ToxException {
    this.lock.lock();
    byte[] ret;

    try {
      checkPointer();
      ret = toxav_prepare_video_frame(this.avPointer, callIndex, destMax, data, width, height);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Encode audio frame
  *
  * @param av Handler
    * @param call_index call index
  * @param dest_max Max dest size
  * @param frame The frame
  * @param frame_size The frame size
  * @return byte array on success, else null
  */
  private native byte[] toxav_prepare_audio_frame (long avPointer, int call_index, int dest_max, int[] frame, int frame_size);

  /**
   * Encode audio frame
   * @param callIndex
   * @param destMax
   * @param data
   * @param frameSize
   * @return The encoded audio frame
   * @throws ToxException
   */
  public byte[] avPrepareAudioFrame(int callIndex, int destMax, int[] data, int frameSize) throws ToxException {
    this.lock.lock();
    byte[] ret;

    try {
      checkPointer();
      ret = toxav_prepare_audio_frame(this.avPointer, callIndex, destMax, data, frameSize);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Get peer transmission type. It can either be audio or video.
  *
  * @param av Handler.
    * @param call_index call index
  * @param peer The peer
  * @return codec settings on success
  */
  private native ToxCodecSettings toxav_get_peer_csettings (long avPointer, int call_index, int peer);

  /**
   * Get peer transmission type, either audio or video
   * @param callIndex
   * @param peer
   * @return codec settings
   * @throws ToxException
   */
  public ToxCodecSettings avGetPeerCodecSettings(int callIndex, int peer) throws ToxException {
    this.lock.lock();
    ToxCodecSettings ret;

    try {
      checkPointer();
      ret = toxav_get_peer_csettings(this.avPointer, callIndex, peer);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Get id of peer participating in conversation
  *
  * @param av Handler
    * @param call_index call index
  * @param peer peer index
  * @return peer id
  */
  private native int toxav_get_peer_id (long avPointer, int call_index, int peer );

  /**
   * Get id of peer in conversation
   * @param callIndex
   * @param peer
   * @return peer id
   * @throws ToxException
   */
  public int avGetPeerId(int callIndex, int peer) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_get_peer_id(this.avPointer, callIndex, peer);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }

  /**
  * Get current call state
  *
  * @param av Handler
  * @param call_index What call
  * @return ToxAvCallState
  */
  private native ToxAvCallState toxav_get_call_state (long avPointer, int call_index );

  /**
   * Get call state
   * @param callIndex
   * @return call state
   * @throws ToxException
   */
  public ToxAvCallState avGetCallState(int callIndex) throws ToxException {
    this.lock.lock();
    ToxAvCallState ret;

    try {
      checkPointer();
      ret = toxav_get_call_state(this.avPointer, callIndex);
    } finally {
      this.lock.unlock();
    }

    return ret;
  }
  /**
  * Is certain capability supported
  *
  * @param av Handler
  * @param call_index call index
  * @return 1 yes, 0 no
  */
  private native int toxav_capability_supported (long avPointer, int call_index, ToxAvCapabilities capability );

  /**
   * Check for certain av capability
   * @param callIndex
   * @param capability
   * @return True if exists, otherwise False
   * @throws ToxException
   */
  public boolean avCapabilitySupported(int callIndex, ToxAvCapabilities capability) throws ToxException {
    this.lock.lock();
    int ret;

    try {
      checkPointer();
      ret = toxav_capability_supported(this.avPointer, callIndex, capability);
    } finally {
      this.lock.unlock();
    }

    return ret == 1;
  }

  /* not implemented
      private native long toxav_get_tox(long avPointer);

      private native int toxav_has_activity (long avPointer, int call_index, int[] PCM, int frame_size, float ref_energy );
      */
TOP

Related Classes of im.tox.jtoxcore.JTox

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.