DeveloperDeveloper
  • Standard Solutions
  • Cam Solutions
  • Native SDKs
  • App Gallery
  • Game Engine Plugins
  • AI
Forum
Projects Library
Dev Discord
  • Standard Solutions
  • Cam Solutions
  • Native SDKs
  • App Gallery
  • Game Engine Plugins
  • AI
Forum
Projects Library
Dev Discord
  • Cam Solutions (with Lovense Connect)

    • Introduction
    • Cam Extension for Chrome
    • Cam Kit for Web
    • Display Panel (optional)
    • Take Control
    • Basic API
    • Basic Socket API
    • Basic JS SDK
    • Viewer JS
Got Stuck?
Forum for Lovense Developers
Support
Document Feedback

Take Control

Introduction

Take Control is a new feature in the Lovense Cam Extension. It allows cam models to control tippers' toys. Models need to set up this feature in the Cam Extension while tippers connect their toys via the Vibemate app.

Model Setup

Step 1: Add Take Control from the App Gallery

Add Take Control from the App Gallery in the Lovense Cam Extension.

Add Take Control from the App Gallery

Step 2: Configure Settings

Models can set pricing per minute for controlling viewers' toys.

Configure Take Control settings

Step 3: Control Tippers' Toys

On the viewer's side, the app rules and status will be displayed. Viewer members can scan the QR code and connect their own toys via the Vibemate App in advance. You can also customize the entry point for the Take Control feature on the viewer side.

Viewer rules and status

When viewers successfully scan the QR code and connect their toys in the Vibemate app, they can then tip to let the model control their toys.

Viewer QR code connection

After the viewer/tipper establishes connection, the cam model can start controlling their toy(s) through the control panel until the countdown ends. Models can control toys through the control panel, either manually with their mouse/keyboard or with one of the preset patterns.

Model control panel

Platform Integration Guide

To enable this feature for models on your platform, some adjustments are required according to the following guidelines.

Viewer Side

Step 1: Import the Cam JDK script to the viewer's page

<script src="https://api.lovense-api.com/cam-extension/static/cam-jdk/js/core.min.js"></script>

This script will introduce a global variable LovenseCamJdk that contains two classes Model and Customer.

Step 2: Initialize the instance object

Initialize an instance object using the class Customer.

const { Customer } = window.LovenseCamJdk
const customer = new Customer(initOptions)

Parameters:

NameTypeDescriptionRequired
initOptionsObjectConfiguration object containing keys described below.yes
initOptions.platformStringThis is the Website Name shown in the developer dashboard.yes
initOptions.modelNameStringThe model name encrypted using the AES KEY and AES IV.yes
initOptions.customerNameStringThe viewer name encrypted using the AES KEY and AES IV.yes
initOptions.gameNameStringThis is the name of the specific game. In this case, the value take-control is fixed.yes
initOptions.useLovenseViewBooleanWhether to use the interface provided by Lovense or design your own.no
initOptions.gameWrapHTMLElementThe DOM container that the game interface is embedded into.no

Description:

Lovense has included all the interactive interfaces needed for Take Control. The default is a floating widget on the page. You may also choose to embed it into the page: set aside an empty DOM container and pass it as the initOptions.gameWrap parameter.

Of course, you may also design and implement the interfaces yourself, just set the initOptions.useLovenseView parameter to false. Lovense will provide you with all the data interfaces you need, as shown below.

About the encryption mentioned above, you can get the AES KEY and AES IV from our developer dashboard.

Developer dashboard AES key and IV

Here is a demo on how to encrypt text using AES in JAVA:

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Key;

public class AESDemo {

    private static Key getKey(String key) throws Exception{
        byte[] keyBytes = key.getBytes("UTF-8");
        SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
        return newKey;
    }

    private static AlgorithmParameters getIV(String iv) throws Exception {
        byte[] ivs = iv.getBytes("UTF-8");
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(ivs));
        return params;
    }

    public static String encrypt(String key,String iv,String text) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, getKey(key), getIV(iv));
        byte[] encryptedBytes = cipher.doFinal(text.getBytes());
        return new String(Base64.encodeBase64(encryptedBytes, false,true),"UTF-8");
    }

    public static String decrypt(String key,String iv,String text) throws Exception {
        byte[] textBytes = Base64.decodeBase64(text);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, getKey(key), getIV(iv));
        byte[] decodedBytes = cipher.doFinal(textBytes);
        return new String(decodedBytes, "UTF-8");
    }

    public static void main(String[] args) throws Exception{
        String key="jHZZwiizsAF2qTAY"; //use your own Key here
        String iv="zijknVpNWeeTYGPV"; //use your own IV here
        String test="Hello World!";
        System.out.println(encrypt(key,iv,test));;
        System.out.println(decrypt(key,iv,encrypt(key,iv,test)));;
    }
}

Step 3: Change Model (optional)

If your website is a single page application, when the viewer switches to watching a different model, call the changeModel method to refresh the state.

/**
 * @param {String} modelName The model's name encrypted using the AES KEY and AES IV
 */
customer.changeModel(modelName)

After switching the model, call reactivateGame to re-activate the game for the newly selected model.

customer.reactivateGame()
Example
const { Customer } = window.LovenseCamJdk
const data = {
  platform: "cam site name",
  modelName: "encrypted model name",
  customerName: "encrypted view name"
}
let customer = null

const initTakeControl = () => {
  customer = new Customer({
    platform: data.platform,
    modelName: data.modelName,
    customerName: data.customerName,
    gameName: "take-control"
  })
}
initTakeControl()

Viewer Side Data API

If you choose to implement your own interface or show some additional interfaces on the model's streaming page, use the following data API.

Method

getGameSetting

Get the model's game settings configuration and game status.

/**
 * @returns {Promise} gameSettingResponse
 * gameSettingResponse: {
 *   gameSetting: Object|Array|null, // game settings configuration
 *   isAppStart: Boolean // game enable status
 * }
 */
customer.getGameSetting()

// example
const gameSettingResponse = await customer.getGameSetting()

getGameStatus

Get information about the current viewer's game status.

/**
 * @returns {Promise} gameStatusResponse
 * gameStatusResponse: {
 *   qrCode: String, // QR code information
 *   status: Number, // game status:
 *                   // 1 not connected via the Vibemate app QR code
 *                   // 2 Vibemate app connected but no toy connected
 *                   // 3 toy connected, ready
 *                   // 4 currently being controlled
 *   modelName: String, // current model's name
 *   followModelName: String // name of the model who is controlling this viewer
 * }
 */
customer.getGameStatus()

// example
const gameStatusResponse = await customer.getGameStatus()

getGameRunningInfo

Get real-time info about Take Control while it is currently running.

/**
 * @returns {Promise} runningInfoResponse
 * runningInfoResponse: {
 *   pf: String, // cam site name
 *   excessTime: Number, // remaining time
 *   totalTime: Number, // total duration
 *   joinNum: Number, // number of viewers who tip and scan the code to join Take Control
 *   toyNum: Number, // number of toys controlled
 *   modelName: String, // model's name
 * }
 */
customer.getGameRunningInfo()

// example
const runningInfoResponse = await customer.getGameRunningInfo()

Event

ready

This event is triggered when game initialization is complete. The above methods on the viewer side are only valid if the ready event is triggered.

/**
 * @returns {Object} customer instance
 */
customer.on("ready", (instance) => {})

update-game-setting

This event is triggered when the model turns Take Control on or off.

/**
 * @returns {Object} payload
 * payload: {
 *   gameSetting: Object|Array|null, // game settings configuration
 *   isAppStart: Boolean // the game enabling status
 * }
 */
customer.on("update-game-setting", (payload) => {})

update-game-status

This event is triggered when the current viewer's game status changes.

/**
 * @returns {Object} payload
 * payload: {
 *   qrCode: String, // QR code information
 *   status: Number,
 *   modelName: String, // current model's name
 *   followModelName: String // name of the model who is controlling this viewer
 * }
 */
customer.on("update-game-status", (payload) => {})

update-game-running-info

This event is triggered when game runtime information is updated.

/**
 * @returns {Object} payload
 * payload: {
 *   pf: String, // cam site name
 *   excessTime: Number, // remaining time
 *   totalTime: Number, // total duration
 *   joinNum: Number, // number of viewers who tip and scan the code to join Take Control
 *   toyNum: Number, // number of toys controlled
 *   modelName: String, // model's name
 * }
 */
customer.on("update-game-running-info", (payload) => {})

update-toy-command

This event is triggered when there is a new toy command sent.

/**
 * @returns {Object} payload
 * payload: {
 *   vibration: Number, // vibration level, value interval: 0~20
 *   rotation: Number, // rotation level, value interval: 0~20
 *   air: Number, // air level, value interval: 0~20
 * }
 */
customer.on("update-toy-command", (payload) => {})

game-exit

Triggered at the end of the game.

/**
 * @returns {Object} payload
 * payload: {
 *   type: Number, // ending Type, 1: model ends their broadcast 2: model disables Take Control 3: Take Control session ends
 * }
 */
customer.on("game-exit", (payload) => {})
Last Updated:
Explore our Forum or Support to get more inspiration or solve your problems.
Discord Channel
It is an online real-time channel where you can communicate directly with our official administrators or many excellent developers.
Forum
It is a place for Lovense developers to communicate, where you can find solutions to problems or get inspired for your projects.
Support
Find documents and tutorials that may be helpful to you.