doc:appunti:hardware:sjcam-8pro-ambarella-wifi-api

SJCAM SJ8 Pro WiFi Ambarella API

When the WiFi is on, the camera has the IP address 192.168.42.1 and you can connect to it on the SJ8PRO_XXXXXX_2.4G ESSID with the default password 12345678 (only one client at a time is allowed). The camera offers an API over the TCP protocol on port 7878; you can open a TCP connection with it and exchange JSON messages to control the camera. This is the interface used by the official app.

The server on the camera accepts only one client at a time. When the camera is connected to a WiFi client on the controlling port 7878/TCP it will ignore the Auto Power Off setting and it remains active.

The protocol was at least partially reversed engineered. Having a rooted Android phone, it was possibile to run the tcpdump tool to analyze the TCP traffic (tcpdump is installed from the command line of the Termux app). As root I started tcpdump to capture the traffic exchanged from the smartphone and the SJCAM camera, while using the SJCAM Zone app.

See my other page about the SJCAM SJ8 Pro action camera:

JSON Messages

This is what a JSON message sent from the host (e.g. the Android smartphone) to the SJ8 Pro looks like:

{"param":"2022-04-25 10:29:59","msg_id":2,"type":"camera_clock","token":2}

The most important item of the message is the msg_id, for each code there may be other parameters that must be instantiated, usually type and param. The token represents the current session and must be obtained first.

The first message sent from the host is the AMBA_START_SESSION (msg_id 257):

{"msg_id":257,"token":0}

the answer from the SJCAM is something like this:

{"rval":0,"msg_id":257,"param":1}

The returned value rval should be zero, generally a negative number means some error occurred. The token is received into the param item, it is an integer increasing by one on every new connection.

NOTICE: Response messages from the SJCAM do not end with a new line character.

Ambarella msg_id Codes

The names of the Ambarella codes (the first column in the following table) were taken from various sources on the net (see web_references). Some were named by me, because I did not find any documentation about them (the ones prefixed with ???).

Ambarella Name Value Use
AMBA_START_SESSION 257 Get initial session token.
AMBA_STOP_SESSION 258 Terminate the session.
AMBA_GET_SETTING 1 Get the value of a a single camera setting.
AMBA_SET_SETTING 2 Set the value of a camera setting. Settings are the ones returned by AMBA_GET_ALL_CURRENT_SETTINGS, plus some others, like camera_clock, camera_mode, save_low_resolution_clip, stream_out_type, …
AMBA_GET_ALL_CURRENT_SETTINGS 3 Get current camera settings. Notice: some settings appear more than once, but setting one will change all of them.
AMBA_GET_SPACE 5 Get card space, total and free.
AMBA_NOTIFICATION 7 Notification message. Generally this message is not an answer to a previous host message and it does not contain the rval item.
AMBA_GET_SINGLE_SETTING_OPTIONS 9 Get the list of values accepted by a setting.
AMBA_GET_DEVICEINFO 11 Get camera brand, model, firmware and API version, etc.
??? AMBA_CAMERA_OFF 12 Power off the camera. The message must contain the item param:cam_off.
AMBA_GET_BATTERY_LEVEL 13 Get power state and battery charge percent.
AMBA_BOSS_RESETVF 259 Start video streaming from the camera using RTSP on port 554/TCP. Re-enable the shutter button after an AMBA_STOP_VF message. The message fails if the camera is displaying some settings screen. The code is referenced with different names in other sources: sendResetVF, sendForceResetVF; probably it is used by other firmwares to control the viewfinder.
AMBA_STOP_VF 260 Stop the video streaming on port 554/TCP. In the SJCAM SJ8 Pro this message disables the shutter button.
AMBA_RECORD_START 513 Start recording (timelapse, burst, …)
AMBA_RECORD_STOP 514 Stop recording.
AMBA_GET_RECORD_TIME 515 Get current recording length in seconds.
AMBA_TAKE_PHOTO 769 Take a photo.
??? AMBA_GET_CURRENT_MODE_SETTINGS 2053 Get current mode (video, photo, etc.) settings. It returns a subset of the AMBA_GET_ALL_CURRENT_SETTINGS message.
??? AMBA_SET_WIFI 2055 Change the WiFi connecting parameters (effective after a reboot). The message must contain type:ESSID and param:SecretPassword. The ESSID will be suffixed by _2.4G or _5G depending on the WiFi setting and the password will be truncated to eight characters.

Examples

AMBA_START_SESSION

Start an API session and get the session token. In this case the returned token to be used in subsequent messages is 2, the token is an integer increasing for every new session established:

SEND: {"msg_id":257,"token":0}
RECV: {"rval":0,"msg_id":257,"param":2}
AMBA_STOP_SESSION

To close celanly the controlling session:

SEND: {"msg_id":258,"token":2}
RECV: {"rval":0,"msg_id":258}
AMBA_GET_DEVICEINFO
SEND: {"msg_id":11,"token":2}
RECV: {"rval":0,"msg_id":11,"brand":"SJCAM","model":"SJ8PRO_TAIWAN","chip":"A12","app_type":"Connected",
  "fw_ver":"local","api_ver":"4.1.0","media_folder":"/tmp/SD0/DCIM","event_folder":"/tmp/SD0EVENT",
  "http":"Disable","auth":"off","naming_rule":[{"type":"video","main_section":[0,6],
  "sensor_section":[6,1],"stream_section":[7,1]},{"type":"photo","main_section":[0,6],
  "offset_section":[6,2]}],"firmwareVersion":"V1.3.2"}
AMBA_GET_ALL_CURRENT_SETTINGS
SEND {"msg_id":3,"token":2}
RECV: {"rval":0,"msg_id":3,"param":[{"Resolution":"1440 (2560x1440) 60FPS"},{"Power-On Record":"Off"},
  {"Video Lapse Resolution":"4K (3840x2160)"},{"Video Lapse":"1 Second"},{"Slow Motion":"-2X"},
  {"Image Size":"12MP 4000x3000 4:3"},{"Photo ISO":"Auto"},{"Shutter Speed":"Auto"},
  {"Photo Sharpness":"Standard"},{"Image Size":"12MP 4000x3000 4:3"},{"Photo Lapse Interval":"3 Seconds"},
  {"Photo Sharpness":"Standard"},{"Time photo ISO":"Auto"},{"Time photo shutter":"Auto"},
  {"Image Size":"12MP 4000x3000 4:3"},{"Burst Mode":"3 photos"},{"Burst ISO":"Auto"},
  {"Video_photo Resolution":"1080(1920x1080) 30FPS"},{"Photo Interval":"5 Seconds"},
  {"Resolution":"1440 (2560x1440) 60FPS"},{"EV":"+0.0"},{"White Balance":"Auto"},
  {"Color Profile":"SJCAM - Vivid"},{"Metering Mode":"Center"},{"Gyro Stabilizer":"On"},
  {"Encoding":"H.264"},{"Volume":"8"},{"Sharpness":"Standard"},{"Distortion Correction":"On"},
  {"Loop Recording":"Off"},{"File Size":"5 Minutes"},{"Video Quality":"Standard"},{"ISO":"MAX 6400"},
  {"Audio":"On"},{"Time Stamp":"Off"},{"EV":"+0.0"},{"White Balance":"Auto"},
  {"Color Profile":"SJCAM - Vivid"},{"Metering Mode":"Center"},{"Time Stamp":"Off"},
  {"Distortion Correction":"On"},{"RAW":"Off"},{"Photo Quality":"Standard"},{"Language":"en"},
  {"Format":"Cancel"},{"Auto Power Off":"3 Minutes"},{"LCD Off Time":"30 Seconds"},
  {"Front Display":"Off"},{"Indicator lights":"Off"},{"Keypad Tone":"On"},{"Rotate":"Off"},
  {"External microphone":"Off"},{"Gimbal Control":"Off"},{"Frequency":"50 Hz"},
  {"Default Setting":"Cancel"},{"Display ISO":"On"},{"User Interface":"Classic"}]}'
AMBA_GET_SETTING

With this command you can get the current value of one of the settings returned by AMBA_GET_ALL_CURRENT_SETTINGS, plus some camera settings like camera_clock, camera_mode, save_low_resolution_clip, stream_out_type, …

Get camera current mode (for the SJ8Pro the mode is one of normal_record, timelapse_video, slow_video, normal_capture, timelapse_photo, burst_capture, car_mode);

SEND: {"msg_id":1,"type":"camera_mode","token":2}
RECV: {"rval":0,"msg_id":1,"type":"camera_mode","param":"normal_record"}
AMBA_GET_SINGLE_SETTING_OPTIONS

Enumerate all the possible values for LCD Off Time setting:

SEND: {"msg_id":9,"param":"LCD Off Time","token":2}
RECV: {"rval":0,"msg_id":9,"permission":"settable","param":"LCD Off Time",
       "options":["Off","30 Seconds","1 Minute","3 Minutes","5 Minutes"]}

Enumerate all the possible values for Resolution setting:

SEND: {"msg_id":9, "param": "Resolution", "token":1}
RECV: {"rval":0,"msg_id":9,"permission":"settable","param":"Resolution","options":[
       "4K (3840x2160) 24FPS","4K (3840x2160) 25FPS","4K (3840x2160) 30FPS",
       "4K (3840x2160) 50FPS","4K (3840x2160) 60FPS",
       "4K UItra (3840X21 60) 24FPS","4K UItra (3840X2160) 30FPS",
       "2.7K (2720x1520) 24FPS","2.7K (2720x1520) 25FPS","2.7K (2720x1520) 30FPS",
       "2.7K (2720x1520) 50FPS","2.7K (2720x1520) 60FPS",
       "1440 (2560x1440) 24FPS","1440 (2560x1440) 25FPS","1440 (2560x1440) 30FPS",
       "1440 (2560x1440) 50FPS","1440 (2560x1440) 60FPS",
       "1080(1920x1080) 24FPS","1080(1920x1080) 25FPS","1080(1920x1080) 30FPS",
       "1080(1920x1080) 50FPS","1080(1920x1080) 60FPS","1080(1920x1080) 120FPS",
       "1080 Ultra(1920X1080) 30FPS","1080 Ultra(1920X1080) 60FPS",
       "720(1280x720) 240FPS"]}
AMBA_SET_SETTING

Change one setting of the camera:

SEND: {"msg_id":2,"type":"LCD Off Time","param":"30 Seconds","token":2}
RECV: {"rval":0,"msg_id":2,"type":"LCD Off Time"}

Set the clock of the camera:

SEND: {"msg_id":2,"type":"camera_clock","param":"2022-05-06 17:02:43","token":2}
RECV: {"rval":0,"msg_id":2,"type":"camera_clock"}

Set the video mode:

SEND: {"msg_id": 2, "type": "Resolution", "param": "1080(1920x1080) 30FPS", "token":1}
RECV: {"rval":0,"msg_id":2,"type":"camera_mode"}

Set the camera mode to normal record:

SEND: {"msg_id": 2, "type": "camera_mode", "param": "normal_record", "token":1}
RECV: {"rval":0,"msg_id":2,"type":"camera_mode"}{"msg_id":7,"type":"normal_record"}
AMBA_GET_RECORD_TIME

Returns the length of current recording, in seconds:

SEND: {"msg_id":515,"token":2}
RECV: {"rval":0,"msg_id":515,"param":132}

In case of error (e.g. the camera is not recording video):

RECV: {"rval":-1,"msg_id":514}
AMBA_GET_SPACE

Get total and free space of SD card:

SEND: {"msg_id":5,"type":"total","token":2}
RECV: {"rval":0,"msg_id":5,"param":61765632}
SEND: {"msg_id":5,"type":"free","token":2}
RECV: {"rval":0,"msg_id":5,"param":51504768}
AMBA_GET_BATTERY_LEVEL

Camera is attacchet to the power adapter and battery is fully charged:

SEND: {"msg_id":13,"token":2}
RECV: {"rval":0,"msg_id":13,"type":"adapter","param":100}

Camera is on battery, at about 25% charge:

RECV: {"rval":0,"msg_id":13,"type":"battery","param":25}
AMBA_BOSS_RESETVF

Sending the following two messages will start the RTSP video streaming server on port 554/TCP:

SEND: {"param":"rtsp","msg_id":2,"type":"stream_out_type","token":2}
RECV: {"rval":0,"msg_id":2,"type":"stream_out_type"}
SEND: {"msg_id":259,"param":"none_force","token":2}
RECV: {"rval":0,"msg_id":259}
AMBA_STOP_VF

To stop the RTSP video stream:

SEND: {"msg_id":260,"token":2}
RECV: {"rval":0,"msg_id":260}

FIXME

SEND: {"param":"on","msg_id":2,"type":"save_low_resolution_clip","token":2}

Notification messages

Into the controlling session you can sometimes get some messages with msg_id AMBA_NOTIFICATION; they inform you about events occurred in response of other commands or by touch screen operations. Here are some examples:

{"msg_id":7,"type":"menu_on"}
{"msg_id":7,"type":"Resolution","param":"2"}
{"msg_id":7,"type":"Gyro Stabilizer","param":"0"}
{"msg_id":7,"type":"menu_off"}
{"msg_id":7,"type":"start_normal_record"}
{"msg_id":7,"type":"stop_normal_record"}

Video streaming

The camera can also stream video to the attached host. Using tcpdump you can observe a session on port TCP/554 where the parts negotiate an RTSP session, then you can see an UDP flow originating from camera UDP ports 6970-6971.

Just as an example, here it is an RTPS answer from the camera:

RTSP/1.0 200 OK
CSeq: 5
Date: Mon, Apr 25 2022 10:30:00 GMT
Range: npt=0.000-
Session: A232310F
RTP-Info: url=rtsp://192.168.42.1/live/track1;seq=35674;rtptime=0

Using the AMBA_BOSS_RESETVF command explained above you can initiate the RTSP video stream and visualize it using VLC from the same controlling client (I used my GNU/Linux box for both to talk to the API port 7878/TCP and to play VLC):

vlc rtsp://192.168.42.1:554/live

Using Python to call the API

Termux Widgets to start SJCAM scripts Termux screen on Android smartphone I wrote same Python scripts to execute simple actions, like start and stop recording, turning off the front LCD and LEDs. Python is very flexible: I can run the same scripts from my GNU/Linux PC or from the Android smartphone (once I installed the Termux app). Here it is a screenshot of the script launched from an icon on my Android device:

On Android I installed also the Termux:Widget app which allows to add shortcut icons over the desktop which will launch the scripts. I have scripts to start and stop recording, to change white balance, to turn ON and OFF the front display and to power OFF the camera. Each launcher was customized with its own icon (se the screenshot to the left). When a script is launched, the output is printed into the text console; to have a more visible feedback I used the figlet program to print large ASCII-art messages (se the screenshot to the right).

In this GitHub repository you can find a Python module which contains basic functions to send and receive the JSON messages, plus some handy scripts to do basic operations, like REC Start, REC Stop, set White Balance, etc.

Executing API commands at bootstrap

It is possible to automatically execute some API calls at camera bootstrap, without connecting any WiFi device to the camera itself.

In this scenario the RTOS operating system on the camera uses the telnet command to talk to the GNU/Linux operating system running on the same camera, which handles the API requests (the camera actually runs two operating system simultaneusly: RTOS and Linux).

I was able to create a script to select the Color Profile automatically at boot. Remember that, due a firmware bug, the color profile choice is not preserved across reboots, and you have to disable the Gyro Stabilizer before selecting the Color Profile.

NOTICE: I had written this script because I had customized the SJCAM - Vivid profile and I wanted to select it at bootstrap, while the camera starts with a default profile which at the time I did not know how to customize. Today BitrateEditor exposes also the default profile, so I can customize every profile and this script is now useless for me.

Executing that script at camera startup is a rather convoluted process:

  • At bootstrap, the RTOS executes the autoexec.ash Ambarella Script.
  • Using the command t ipc rpc clnt exec2 it is possible to execute a script into the GNU/Linux operating system.
  • The GNU/Linux environment has the busybox software, so it is possible to use the telnet command to establish a TCP connection with the API server at localhost:7878.
  • The required JSON commands are sent to the API server to disable Gyro Stabilizer, select the Color Profile and then re enable Gyro Stabilizer.

WARNING: It seems that the API implementation is rather buggy. I experienced several problems ranging from commands not aknowledged if sent with bad timing (not waiting enough time from one command to the next), even to suddenly reboot!

Here there are the three files that must be created on the root directory of the SD card:

autoexec.ash

sleep 5000
t ipc rpc clnt exec2 '/tmp/SD0/autoexec.rc'

autoexec.rc

#!/bin/sh
/tmp/SD0/api-set-options

api-set-options

#!/bin/sh
#
# Send some commands to the TCP:7878 API.
# Set the color profile to "SJCAM - Vivid" and enable Gyro Stabilizer.

# We should get the token number from msg_id 257, but this script
# is executed at boot, so the token should be always "1".
T=1

# A pause of 0.5 is required for each command to be completed.
# By trial we discovered that a pause of 0.4 is not sufficient.
S=0.52

{
  echo '{"msg_id": 257, "token": 0}'; sleep 1.5;
  echo '{"msg_id": 2, "type": "Gyro Stabilizer", "param": "Off",           "token": '$T'}'; sleep $S;
  echo '{"msg_id": 2, "type": "Color Profile",   "param": "Flat",          "token": '$T'}'; sleep $S;
  echo '{"msg_id": 2, "type": "Color Profile",   "param": "SJCAM - Vivid", "token": '$T'}'; sleep $S;
  echo '{"msg_id": 2, "type": "Gyro Stabilizer", "param": "On",            "token": '$T'}'; sleep $S;
  sleep 1.0;
} | telnet localhost 7878
echo

Web References

doc/appunti/hardware/sjcam-8pro-ambarella-wifi-api.txt · Last modified: 2023/06/16 10:18 by niccolo