React native (expo)

It’s a stream.

See these articles

livePreview, MotionJPEG on RICOH THETA - Acquiring the Data Stream

RICOH THETA SC2 livePreview MotionJPEG Single Frame Extraction

This example is in Dart. The main idea is that normally, the HTTP request will close the HTTP connection. There is likely an option to keep the stream open with the JavaScript library you are using. You can then listen to the stream and get the individual JPEG frames to display.

import 'dart:convert';
import 'dart:io';

void main() async {
  Uri apiUrl = Uri.parse('http://192.168.1.1/osc/commands/execute');
  var client = HttpClient();
  Map<String, String> body = {'name': 'camera.getLivePreview'};
  var request = await client.postUrl(apiUrl)
    ..headers.contentType = ContentType("application", "json", charset: "utf-8")
    ..write(jsonEncode(body));
  var response = await request.close();
  response.listen((List<int> data) {
    print(data);
  });
}

If you are familiar with Python, you can also quickly test and view it with this article.

This code has an example of displaying the preview in react native. Maybe you can use it as a reference.

Hi, Thanks! I am using this @goroya.io/theta-api-client library! i tried to use addListener but i really cant debug my app as i am using web apis and i have to connect to richon wifi and if i connect then i lost the expo node connection!

constructor(props) {
    super(props);
    this.state = { thetaIP: '192.168.1.1',dataUrl:'',isLoading:false,live:null };
    this.thetaClient = new ThetaHttpClient({
      hostname: '192.168.1.1',
      axiosConfig: {},
      auth: { user: 'THETAYP00153401.OSC', pass: '00153401' }
    });
    this.onPressTakePicture = this.onPressTakePicture.bind(this);
    this.livePreview = this.livePreview.bind(this);
    this.getStatus = this.getStatus.bind(this);
  }


componentDidMount() {
    let subscribing = this.thetaClient.addListener("cameraGetLivePreview",event => {
      console.warn(event,'event')
    });
    return () => {
      subscribing.removeAllListeners();
    };
     this.livePreview();
  }

async livePreview() {
    console.log("take start");
    const res = await this.thetaClient 
    .cameraGetLivePreview({
      baseURL: `http://${this.state.thetaIP}`,
    })
    .catch(e => {
      console.error('cameraGetLivePreview:', e);
    });
    console.warn(res.data,'cameraGetLivePreview res')
  }

Doing something like this!
I know i am doing it wrong i guess

i tried to use addListener but i really cant debug my app as i am using web apis and i have to connect to richon wifi and if i connect then i lost the expo node connection!

Unless your home Internet router is at 192.168.1.x, you can put another WiFi adapter into your computer and connect it to both the Internet and your camera at the same time. If you have access to the Internet router, you can assign your router another IP address like 192.168.101.1.

auth: { user: 'THETAYP00153401.OSC', pass: '00153401' }

Unless the RICOH THETA is in Client Mode (which the SC2 does not support), then you do not need the username and password.

Does it work without auth?

this.state = { thetaIP: '192.168.1.1',dataUrl:'',isLoading:false,live:null };

What does live:null refer to?

I have not used the library you are referring to.

Here is my code, take picture is working but the cameraGetLivePreview is not working i tried to debug it but its not working, at all dont know why tried with the fetch command as well still debug is not stopping at breakpoint nor the console error

import React, {useEffect, useRef, useState} from 'react';
import {ThetaHttpClient} from '@goroya.io/theta-api-client';
import {View, Image, Button} from 'react-native';

const LivePreview = () => {
  const [image, setImage] = useState('');
  const [clickUrl, setClickUrl] = useState('');
  const [isLoading, setIsLoading] = useState('');
  const THETA_IP_ADDRESS = '192.168.1.1';

  const thetaClient = new ThetaHttpClient({
    hostname: '192.168.1.1',
    axiosConfig: {},
    auth: {user: 'THETAYP00153401.OSC', pass: '00153401'},
  });
  const [imageData, setImageData] = useState('');
  const previewUrl = 'http://192.168.1.1/osc/commands/execute';
  const payload = {
    name: 'camera.getLivePreview',
    parameters: {},
  };

  const handlePreviewData = data => {
    const reader = new FileReader();
    reader.onload = () => {
      setImageData(reader.result);
    };
    reader.readAsDataURL(data);
  };

  const streamPreview = async () => {
    const response = 
// await fetch(previewUrl, {
      //   method: 'POST',
      //   headers: {
      //     'Content-Type': 'application/json;charset=utf-8',
      //   },
      //   body: JSON.stringify(payload),
      // });
      await thetaClient
        .cameraGetLivePreview({
          baseURL: 'http://192.168.1.1',
        })
        .catch(e => {
          console.log(e, 'streamPreview');
        });

    const reader = response.body.getReader();

    while (true) {
      const {done, value} = await reader.read();
      if (done) {
        break;
      }
      const stringValue = new TextDecoder().decode(value);
      const boundaryIndex = stringValue.indexOf('---osclivepreview---');
      if (boundaryIndex !== -1) {
        const imageData = stringValue.slice(boundaryIndex);
        handlePreviewData(imageData);
      }
    }
  };
  useEffect(() => {
    streamPreview();

    return () => {
      setImageData('');
    };
  }, []);

  const getStatus = async lastId => {
    console.log('getStatus');
    const axiosConfigBase = {baseURL: 'http://192.168.1.1'};
    const res = await thetaClient.oscCommandsStatus(lastId, axiosConfigBase);
    if (res.data.state === 'inProgress') {
      getStatus(res.data.id);
    } else if (res.data.state === 'done') {
      console.warn(res, 'its complete');
      setIsLoading(false);
      setClickUrl(res?.data?.results?.fileUrl);
    }
  };

  const onPressTakePicture = async () => {
    console.log('take start');
    const res = await thetaClient
      .cameraTakePicture({
        baseURL: 'http://192.168.1.1',
      })
      .catch(e => {
        console.error('error:', e);
      });
    // console.warn(res,"cameraTakePicture");
    if (res?.data?.state === 'inProgress') {
      setIsLoading(true);
      console.log('inProgress');
      await getStatus(res.data.id);
    }
  };

  return (
    <View style={{flex: 1, marginTop: '20%', alignItems: 'center'}}>
      <Button
        style={{borderWidth: 1}}
        onPress={streamPreview}
        title={'Live preview'}
      />
      <Image
        style={{borderWidth: 1, height: 100, width: 100}}
        source={{uri: imageData}}
        alt="Live preview"
      />
      <Button
        style={{borderWidth: 1}}
        onPress={onPressTakePicture}
        title={'Take picture'}
      />
      <Image
        style={{borderWidth: 1, height: 100, width: 300}}
        source={{uri: clickUrl}}
        alt="Live preview"
      />
    </View>
  );
};

export default LivePreview;

Try this to read a stream and display it to the console for testing.

const body = {'name': 'camera.getLivePreview'}
const response = await fetch('http://192.168.1.1/osc/commands/execute', 
	{method: 'POST', 
	body: JSON.stringify(body),
	headers: {'Content-Type': 'application/json'}
});
const data =  response.body

const reader = data.getReader()

while (true) {
	const {value, done} = await reader.read();
	if (done) break;
	console.log('Received', value);
}

console.log(data);

fake-theta no camera version

const body = {'name': 'camera.getLivePreview'}
const response = await fetch('https://fake-theta.vercel.app/osc/commands/execute', 
	{method: 'POST', 
	body: JSON.stringify(body),
	headers: {'Content-Type': 'application/json'}
});
const data =  response.body

const reader = data.getReader()

while (true) {
	const {value, done} = await reader.read();
	if (done) break;
	console.log('Received', value);
}

console.log(data);

expected output

Tested with RICOH THETA X.

Received Uint8Array(13140) [
  154,  66, 105,   9, 166, 147,  64,  10,  90, 155, 145,  77,
   38, 144, 154,   0, 121, 106, 137, 159,  61,  41, 174, 212,
  176, 198, 100,  97, 143, 186,  40,   2,  72, 163,  50,  31,
  106, 191,  12,  33,  71,   2, 146,  24, 192,   2, 173,  34,
  208,   0, 171,  82, 129,  72,   5,  60,  80,  32,   2, 156,
   41,   5,  45,  48,  22, 138,  40, 160,   5, 162, 138,  40,
    1, 104, 164, 165, 160,   2, 138,  40, 160,   5, 162, 146,
  150, 128,  10,  40, 162, 128,  22, 138,  74,  90,   0,  41,
  105,  41, 104,   0,
  ... 13040 more items
]
Received Uint8Array(12525) [
  120, 181,  98,  49,  36, 150, 249, 104, 219,   0, 118, 237,
   86, 173, 245,  72, 159,  11,  48, 242, 143, 169, 233,  85,
  102, 251, 141, 244,  53, 156, 188, 163, 231, 168, 197,  84,
  100, 209,  50, 138, 102, 165, 222, 179,  28,  74, 198,  37,
   46,  71, 115, 210, 185, 251, 173,  74, 238, 231, 115,  73,
   39, 238, 201,  35, 104, 192,  31,  79, 122, 146, 114,   2,
   50, 142,  73,  24,   2, 179,  87,  12, 141, 146, 114,  62,
  232, 237,  90,  39, 115,  54, 172, 105, 198,  75,   0,  73,
  201, 245, 173,  72,
  ... 12425 more items
]

viewing stream as images

I have not tested the code below, but reading through it, the primary algorithms look like it could be used on the stream.

Advice on React Native Expo Courses?

As I don’t know React Native, I am thinking of taking an online course.

I found these two:

I’m more interested in the Meta course on Coursera as it has a higher rating. I’ve already watched a few of the videos and it looks good.

Are you taking an online course for React Native expo?