Windows compatibility with the Sony Camera Remote API - windows

In the "How to develop an app using the Camera Remote API" toturial it states "The Camera Remote API uses JSON-RPC over HTTP. You can therefore use the Camera Remote APIs with any operating system, such as Android, IOS or Microsoft® Windows®." This stands to reason since the protocols are platform-agnostic. However, in the camera compatibility chart on this page:http://developer.sony.com/develop/cameras/ it states that the Sony Smart Remote Control App must be installed in order to "enable the use of the APIs." Since that app is only iOS and Android, does that mean that the APIs cannot be used on Windows?
I am keenly interested in developing a remote control app for Windows 8 tablets, and then for the Windows 8 phone. But if I cannot control the A5000, A7R, A7, NEX-6, NEX-5R, or NEX-5T, then it becomes far less interesting.
Is it possible to control those cameras with the plain HTTP JSON communication?
Thank you

I don't know if you solved your problem but I have the same issue and I managed to make it work somehow with C++. It took me some time to figure out what I had to do, I have never done any HTTP stuff, even less developed plug and play drivers so I will explain how I did it step by step, as I wish I had been explained.
At the end of the message I have given a link to my entire file, feel free to try it.
I am using boost asio library for every network related issue, and more (everything asynchronous really, this is a great library but very hard to grasp for ignorant people like me...). Most of my functions are partially copy-pasted from the examples in the documentation, this explains why my code is awkward at places. Here is my main function, nothing fancy I instanciate an asio::io_service, create my object (that I wrongly named multicast_manager) and then run the service:
#include <bunch_of_stuff>
using namespace std;
namespace basio = boost::asio;
int main(int argc, char* argv[]) {
try {
basio::io_service io_service;
multicast_manager m(io_service, basio::ip::address::from_string("239.255.255.250"));
io_service.run();
m.parse_description();
m.start_liveview();
io_service.reset();
io_service.run();
m.get_live_image();
io_service.reset();
io_service.run();
} catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
Discovering the camera over ssdp
First, we have to connect to the camera using its upnp (universal plug and play) feature. The principle is that every upnp device is listening to the multicast port 230.255.255.250:1900 for M-SEARCH request. It means that if you send the proper message to this address, the device will answer by telling you it exists, and give you information to use it. The proper message is given in the documentation. I ran into two pitfalls doing that: first, I omitted to add the newline at the end of my message, as specified in the http standard. So the message you want to send can be build like that:
multicast_manager(basio::io_service& io_service, const basio::ip::address& multicast_address)
: endpoint_(multicast_address, 1900),
socket_(io_service, endpoint_.protocol())
{
stringstream os;
os << "M-SEARCH * HTTP/1.1\r\n";
os << "HOST: 239.255.255.250:1900\r\n";
os << "MAN: \"ssdp:discover\"\r\n";
os << "MX: 4\r\n";
os << "ST: urn:schemas-sony-com:service:ScalarWebAPI:1\r\n";
os << "\r\n";
message_ = os.str();
// ...
The second thing important in this part is to check that the message is sent to the right network interface. In my case, even when it was disabled, it went out through my ethernet card until I changed the right option in the socket, and I solved this issue with the following code:
// ...
socket_.set_option(basio::ip::multicast::outbound_interface(
basio::ip::address_v4::from_string("10.0.1.1")));
socket_.async_send_to(
basio::buffer(message_), endpoint_,
boost::bind(&multicast_manager::handle_send_to, this,
basio::placeholders::error));
}
Now we listen. We listen from where you might ask if you are like me? What port, what address? Well, we don't care: The thing is, when we sent our message, we defined a destination ip and port (in the endpoint constructor). We didn't necessarily define any local address, it is our own ip address (as a matter of fact, we did define it, but only so that it would know which network interface to choose from); and we didn't define any local port, it is in fact chosen automatically (by the OS I guess?). Anyway, the important part is that anyone listening to the multicast group will get our message and know its source, and will respond directly to the correct ip and port. So no need to specify anything here, no need to create a new socket, we just listen to the same socket we sent our message in a bottle:
void handle_send_to(const boost::system::error_code& error)
{
if (!error) {
socket_.async_receive(asio::buffer(data_),
boost::bind(&multicast_manager::handle_read_header, this,
basio::placeholders::error,
basio::placeholders::bytes_transferred));
}
}
If everything goes right, the answer goes along the line of:
HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1800
EXT:
LOCATION: http://10.0.0.1:64321/DmsRmtDesc.xml
SERVER: UPnP/1.0 SonyImagingDevice/1.0
ST: urn:schemas-sony-com:service:ScalarWebAPI:1
USN: uuid:00000000-0005-0010-8000-10a5d09bbeda::urn:schemas-sony-com:service:ScalarWebAPI:1
X-AV-Physical-Unit-Info: pa=""; pl=;
X-AV-Server-Info: av=5.0; hn=""; cn="Sony Corporation"; mn="SonyImagingDevice"; mv="1.0";
To parse this message, I reused the parsing from the boost http client example, except I did it in one go because for some reason I couldn't do an async_read_until with a UDP socket. Anyway, the important part is that the camera received our message; The other important part is the location of the description file DmsRmtDesc.xml.
Retrieving and reading the description file
We need to get DmsRmtDesc.xml. This time we will send a GET request directly to the camera, at the ip address and port specified. This request is something like:
GET /DmsRmtDesc.xml HTTP/1.1
Host: 10.0.0.1
Accept: */*
Connection: close
Don't forget the extra empty line. I don't know what the Connection:close means. The accept line specify the application type of the answer you accept, here we will take any answer. I got the file using the boost http client example, basically I open a socket to 10.0.0.1:64321 and receive the HTPP header which is followed by the content of the file. Now we have a xml file with the address of the webservice we want to use. Let's parse it using boost again, we want to retrieve the camera service address, and maybe the liveview stream address:
namespace bpt = boost::property_tree;
bpt::ptree pt;
bpt::read_xml(content, pt);
liveview_url = pt.get<string>("root.device.av:X_ScalarWebAPI_DeviceInfo.av:X_ScalarWebAPI_ImagingDevice.av:X_ScalarWebAPI_LiveView_URL");
for (bpt::ptree::value_type &v : pt.get_child("root.device.av:X_ScalarWebAPI_DeviceInfo.av:X_ScalarWebAPI_ServiceList")) {
string service = v.second.get<string>("av:X_ScalarWebAPI_ServiceType");
if (service == "camera")
camera_service_url = v.second.get<string>("av:X_ScalarWebAPI_ActionList_URL");
}
Once this is done, we can start sending actual commands to the camera, and using the API.
Sending a command to the camera
The idea is quite simple, we build our command using the json format provided in the documentation, and we send it with a POST http request to the camera service. We will launch the liveview mode, so we send out POST request (we will eventually have to use boost property_tree to build our json string, here I did it manually):
POST /sony/camera HTTP/1.1
Accept: application/json-rpc
Content-Length: 70
Content-Type: application/json-rpc
Host:http://10.0.0.1:10000/sony
{"method": "startLiveview","params" : [],"id" : 1,"version" : "1.0"}
We send it to 10.0.0.1:10000 and wait for the answer:
HTTP/1.1 200 OK
Connection: close
Content-Length: 119
Content-Type: application/json
{"id":1,"result":["http://10.0.0.1:60152/liveview.JPG?%211234%21http%2dget%3a%2a%3aimage%2fjpeg%3a%2a%21%21%21%21%21"]}
We get the liveview url a second time, I don't know which one is better, they are identical...
Anyway, now we know how to send a command to the camera and retrieve its answer, we still have to fetch the image stream.
Fetching an image from the liveview stream
We have the liveview url, and we have the specification in the API reference guide. First thing first, we ask the camera to send us the stream, so we send a GET request to 10.0.0.1:60152:
GET /liveview.JPG?%211234%21http%2dget%3a%2a%3aimage%2fjpeg%3a%2a%21%21%21%21%21 HTTP/1.1
Accept: image/jpeg
Host: 10.0.0.1
And we wait for the answer, that should not take long. The answer begins with the usual HTTTP header:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Pragma: no-cache
CACHE-CONTROL: no-cache
Content-Type: image/jpeg
transferMode.dlna.org: Interactive
Connection: Keep-Alive
Date: Wed, 09 Jul 2014 14:13:13 GMT
Server: UPnP/1.0 SonyImagingDevice/1.0
According to the documentation, this should be directly followed by the liveview data stream wich consists in theory in:
8 bytes of common header specifying if we are indeed in liveview mode.
128 bytes of payload data giving the size of the jpg data.
n bytes of jpeg data.
And then we get the common header again, indefinitely until we close the socket.
In my case, the common header started with "88\r\n" so I had to discard it, and the jpg data was followed by 10 extra bytes before switching to the next frame, so I had to take that into account. I also had to detect automatically the start of the jpg image because the jpg data started with a text containing a number whose signification I ignore. Most probably these error are due to something I did wrong, or something I don't understand about the technologies I use here.
My code works right now but the last bits are very ad hoc and it definitely need some better checking.
It also needs much refactoring to be usable, but it shows how each step works I guess...
Here is the entire file if you want to try it out.
And here is a working VS project on github.

Thank you for your inquiry.
In the A5000, A7R, A7, NEX-6, NEX-5T, NEX-5R cameras, install the below app.
https://www.playmemoriescameraapps.com/portal/usbdetail.php?eid=IS9104-NPIA09014_00-F00002
This app is to be installed IN the camera and started.
Now you can use "Camera Remote API" to control the above camera from any OS.

Related

Trying to send a FIX api message to ctrader server using Ruby but receiving no response

Trying to see if I can get a response from ctrader server.
Getting no response and seems to hang at "s.recv(1024)". So not sure what could be going wrong here. I have limited experience with sockets and network coding.
I have checked my login credentials and all seems ok.
Note: I am aware of many FIX engines that are available for this purpose but wanted to
try this on my own.
ctrader FIX guides
require 'socket'
hostname = "h51.p.ctrader.com"
port = 5201
#constructing a fix message to see what ctrader server returns
#8=FIX.4.4|9=123|35=A|49=demo.ctrader.*******|56=cServer|57=QUOTE|50=QUOTE|34=1|52=20220127-16:49:31|98=0|108=30|553=********|554=*******|10=155|
fix_message = "8=FIX.4.4|9=#{bodylengthsum}|" + bodylength + "10=#{checksumcalc}|"
s = TCPSocket.new(hostname, port)
s.send(fix_message.force_encoding("ASCII"),0)
print fix_message
puts s.recv(1024)
s.close
Sockets are by default blocking on read. When you call recv that call will block if no data is available.
The fact that your recv call is not returning anything, would be an indication that the server did not send you any reply at all; the call is blocking waiting for incoming data.
If you would use read instead, then the call will block until all the requested data has been received.
So calling recv(1024) will block until 1 or more bytes are available.
Calling read(1024) will block until all 1024 bytes have been received.
Note that you cannot rely on a single recv call to return a full message, even if the sender sent you everything you need. Multiple recv calls may be required to construct the full message.
Also note that the FIX protocol gives the msg length at the start of each message. So after you get enough data to see the msg length, you could call read to ensure you get the rest.
If you do not want your recv or read calls to block when no data (or incomplete data) is available, then you need to use non-blocking IO instead for your reads. This is complex topic, which you need to research, but often used when you don't want to block and need to read arbitary length messages. You can look here for some tips.
Another option would be to use something like EventMachine instead, which makes it easier to deal with sockets in situations like this, without having to worry about blocking in your code.

why http should add a binary frame to achieve multiplexing? [duplicate]

This question already has answers here:
Why HTTP/2 does multiplexing altough tcp does same thing?
(3 answers)
Closed last year.
This passage claims that the binary frame layer becomes the base for multiplexing in http for TCP connection, which is confusing to me.
https://developers.google.com/web/fundamentals/performance/http2#design_and_technical_goals
The confusing part is the HTTP client can just send more requests in one TCP connection without waiting for the response and receive the response for the corresponding request. That is the "frame" is the request and response. So why should it add the binary frame?
Let's have a look at what you're suggesting:
the HTTP client can just send more requests in one TCP connection without waiting for the response
So far, so good: I can send "GET /foo" and then immediately "GET /bar" on the same connection.
and receive the response for the corresponding request
So, the server replies "200 OK" with some HTML content, and ... wait, is that for "/foo" or "/bar"? The key word in your own description is "corresponding" - we need some way of saying "this response corresponds to request #1".
And then, halfway through sending the first response, the server finishes handling the other request, and is ready to send part of a different response; but if it jumps in with "200 OK", that's going to appear to be part of the response it's already sending. So we also need to be able to say "this is the start of a new response", and "this content is the continuation of response #2".
To do that, we need a new abstraction: a frame, with a header which can encode details like "the next 100 bytes are the start of response #2, which corresponds to request #1". (I'm not sure if that's exactly how an HTTP/2 frame works, but I think it's roughly the principle.)
We could do that and still keep the protocol human readable (which is what we really mean by "text-based" vs "binary") but there's going to be a lot of these frame headers, so the shorter we can make them, the better. So if we're interested in performance, we can give up on "human readable" as a requirement, and we end up with a binary framing protocol like HTTP/2.

Is there any way to run Tungstenite on the same port as hyper?

I'm trying to make a web server in Rust for a simple browser game. I want the server to be able to deliver pages through HTTPS, but also be able to communicate through WebSockets. I'm planning to put this server on Heroku, but since they only allow one port per application I have to make the WebSocket server operate on the same port as the other HTTPS code.
It seems like this is possible with crates like rust-websocket, but that crate uses an outdated version of hyper and seems to be no longer maintained. The crate tokio_tungstenite is much more up to date.
The problem is that both hyper and tungstenite have their own implementation of the HTTP protocol that WebSockets operate over with no way to convert between the two. This means that once an HTTPS request has been parsed by either hyper or tungstenite there is no way to continue the processing by the other part, so you can't really try to connect the WebSocket and match on an error in tungstenite and process it by hyper, nor can you parse the request by hyper and check if it's a WebSocket request and send it over to tungstenite. Is there any way to resolve this problem?
I think it should be possible to do that, the tungstenite and tokio-tungstenite allow you to specify custom headers (there are helpers functions for that, prefixed with hdr), so depending on the hyper version you use, if you can convert a request to some form, when the headers can be extracted, you can pass them to tungstenite.
You might also want to try warp crate, it's built on top of hyper and it uses tungstenite under the hood for the websocket support, so if you want to write your own version of warp, you can take a look at the source code (the source code may contain hints on how to use hyper and tungstenite together).
You can do it, but it's quite fiddly. You'll have to use tokio-tungstenite, do the handshake yourself (check header, set response headers) and spawn a new future on the runtime that will handle the websockets connection. The new future can be created by calling on_upgrade() on the request body with the latest version of hyper, and the connection can then be passed to tokio_tungstenite::WebSocketStream::from_raw_socket to turn it into a websockets connection.
Example handler (note that this doesn't fully check the request headers and assumes we want an upgrade):
fn websocket(req: Request<Body>) -> Result<Response<Body>, &'static str> {
// TODO check other header
let key = match req.headers().typed_get::<headers::SecWebsocketKey>() {
Some(key) => key,
None => return Err("failed to read ws key from headers"),
};
let websocket_future = req
.into_body()
.on_upgrade()
.map_err(|err| eprintln!("Error on upgrade: {}", err))
.and_then(|upgraded| {
let ws_stream = tokio_tungstenite::WebSocketStream::from_raw_socket(
upgraded,
tokio_tungstenite::tungstenite::protocol::Role::Server,
None,
);
let (sink, stream) = ws_stream.split();
sink.send_all(stream)
.map(|_| ())
.map_err(|err| error!("{}", err))
});
hyper::rt::spawn(websocket_future);
let mut upgrade_rsp = Response::builder()
.status(StatusCode::SWITCHING_PROTOCOLS)
.body(Body::empty())
.unwrap();
upgrade_rsp
.headers_mut()
.typed_insert(headers::Upgrade::websocket());
upgrade_rsp
.headers_mut()
.typed_insert(headers::Connection::upgrade());
upgrade_rsp
.headers_mut()
.typed_insert(headers::SecWebsocketAccept::from(key));
Ok(upgrade_rsp)
}

Wrong response to AT command via socket c++/cli

I want to create simple socket that will communicate with another device via AT commands.
I'm using C++/CLI on Visual 2017.
This is my code
#include "stdafx.h"
#include <conio.h>
using namespace System;
using namespace System::Net;
using namespace System::Net::Sockets;
using namespace System::IO;
int main(array<System::String ^> ^args)
{
int bufferSize = 1024;
array<Byte>^ sendBuffer = gcnew array<Byte>(bufferSize);
array<Byte>^ recvBuffer = gcnew array<Byte>(bufferSize);
try {
// Establish the remote endpoint for the socket.
IPHostEntry^ ipHostInfo = Dns::Resolve("192.168.1.1");
IPAddress^ ipAddress = ipHostInfo->AddressList[0];
IPEndPoint^ remoteEP = gcnew IPEndPoint(ipAddress, 1234);
// Create a TCP/IP socket.
Socket^ socket = gcnew Socket(AddressFamily::InterNetwork,SocketType::Stream, ProtocolType::Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try {
socket->Connect(remoteEP);
// Encode the data string into a byte array.
array<Byte>^ msg = Text::Encoding::ASCII->GetBytes("AT");
// Send the data through the socket.
int bytesSent = socket->Send(msg);
// Receive the response from the remote device.
int bytesRec = socket->Receive(recvBuffer);
Console::WriteLine("Echoed test = {0}", Text::Encoding::ASCII->GetString(recvBuffer, 0, bytesRec));
// Release the socket.
socket->Shutdown(SocketShutdown::Both);
socket->Close();
}
catch (ArgumentNullException^ ane) {
Console::WriteLine("ArgumentNullException : {0}", ane->ToString());
}
catch (SocketException^ se) {
Console::WriteLine("SocketException : {0}", se->ToString());
}
catch (Exception^ e) {
Console::WriteLine("Unexpected exception : {0}", e->ToString());
}
}
catch (Exception^ e) {
Console::WriteLine(e->ToString());
}
_getch();
return 0;
}
For command there, the response is:
Echoed test = ????????
In ASCII there are weird values: 255,251,3,255,251,1,255,254,1,255,253
The answer should be OK or ERROR
I tested it via Telnet on 192.168.1.1 1234 and it was working fine.
Standard warning: While it's certainly possible to write the main body of your application in C++/CLI, it is not recommended. C++/CLI is intended for interop scenarios: where C# or other .Net code needs to interface with unmanaged C++, C++/CLI can provide the translation between the two. For primary development, it is recommended to use C# if you want managed code, or C++ if you want unmanaged.
That said...
The telnet protocol is not, contrary to popular belief, a raw TCP socket. There is a protocol for communicating options between telnet clients.
What you're seeing there are telnet commands sent from the server. These would be received from by your telnet client, and used to modify how it behaves. This is why everything works when you use a real telnet client: It takes those bytes and interprets the commands properly.
I read the Telnet spec for a few minutes, here's what I was able to decode from the data you posted:
255: IAC, "Interpret as command". This is the escape character for all Telnet commands.
251: WILL: Indicates that the server wants to/is performing an option.
3: SUPPRESS-GO-AHEAD: Apparently Telnet is a half-duplex protocol by default, and the "Go Ahead" is the marker for one side to tell the other, "OK, your turn". This option turns it into a full-duplex connection.
255: IAC
251: WILL
1: ECHO: Indicates that the server will echo back the characters that it receives.
255: IAC
254: DON'T: Indicates that the server is requesting that the client not do something.
1: ECHO: Indicates that the server wants the client to not echo back received characters.
255: IAC
253: DO: Indicates that the server wants the client to turn on some option.
OK, so now that we know what's going on, how do we fix this? I see a few options:
You said you wanted to use "AT Commands" to talk to a device. AT commands are what you use to talk to modems. I'm assuming that you have some serial device, possibly a modem, that you have connected to a little converter device that exposes a serial port as a TCP connection. If so, then there may be some option for that converter device to disable the Telnet protocol, and expose it as "raw", or something similar. If this is true, then that's probably the best option.
You can add code to your program to look for the IAC byte, and handle the bytes that follow it. If it's just a few commands at the beginning of the connection, then you can just expect those fixed bytes; if the commands are sent during the connection, you'll need to handle them everywhere. It's up to you how much you want to handle them. (E.g., if the server says DON'T SUPPRESS-GO-AHEAD, will you send the Go ahead command? Ideally you would, but if your particular connection never says that, then perhaps not.)
There may be a telnet library that will handle the protocol stuff for you. I have not searched for this.
Telnet references:
The main RFC, where the IAC byte and the command bytes are defined: https://www.rfc-editor.org/rfc/rfc854
The ECHO option: https://www.rfc-editor.org/rfc/rfc857
The SUPPRESS-GO-AHEAD option: https://www.rfc-editor.org/rfc/rfc858
Not an official reference, but does list the options that can be specified with WILL, WON'T, DO, and DON'T, and the RFCs they're defined in: http://mars.netanya.ac.il/~unesco/cdrom/booklet/HTML/NETWORKING/node300.html

Am I doing something wrong, or does echo.websocket.org not echo back empty payloads?

According to the spec for websockets protocol 13 (RFC 6455), the payload length for any given frame can be 0.
frame-payload-data ; n*8 bits in
; length, where
; n >= 0
I am building a websocket client to this spec, but when I sent echo.websocket.org a frame with an empty payload, I get nothing back. I experience the same using their GUI:
This is troublesome for me, since the way I'm building my client somewhat requires me to send empty frames when I FIN a multi-frame message.
Is this merely a bug in the Echo Test server? Do a substantial number of server implementations drop frames with empty payloads?
And if this is a bug in Echo Test, does anyone know how I might get in touch with them? The KAAZING site only has tech support contact info for their own products.
If you send a data-frame with no payload, there is nothing to echo back. This behaviour is fully correct. However, it might be standard-conform, too, to send back a dataframe with 0 payload, too. The main question is, if the application layer is informed at all, when a dataframe with no payload is received. This is probably not the case in most implementations.
With TCP this is similar: A TCP-Keepalive is a datagram with 0 payload. It is ack'd by the remote TCP-stack, but the application layer is not informed about it (i.e. select() does not return or a read()-syscall remains blocking), which is the expected behaviour.
An application-layer protocol should not rely on the datagrams to structure the data, but should merely expect a stream of bytes without taking regard on how these are transported.
I just tried the echo test on websocket.org with empty payloads and it seems to work fine using Chrome, Safari and Firefox (latest versions of each). Which browser are you using?
Btw, that demo program doesn't abide by any "echo protocol" (afaik), so there's no formal specification that dictates what to do on empty data in a WebSocket set of frames.
If you need help using WebSocket, there are Kaazing forums: http://developer.kaazing.com/forums.

Resources