※この記事の続編を書きました!**こちら**からどうぞ。
ソニーの カメラリモートAPI を利用して、アクションカム(HDR-AZ1)を自作プログラムから遠隔操作してみました。
カメラリモートAPIとは
最近のカメラはWi-Fi接続で遠隔操作できるものが増えています。たいていは各カメラメーカーの専用のアプリからのみ利用可能ですが、ソニーはその通信仕様を公開しており、 誰でも自由にカメラを利用したアプリケーションを作成することが可能 です。
どのカメラだったら使えるの?
残念ながら、カメラリモートAPIはソニー製の全てのデジタルカメラで使えるわけではありません。こちらのページから、リモートAPIに対応している機種を確認することができます。アクションカムは全機種対応で、その他のデジカメも2013年頃の機種から対応しています。
どうやって使うの?
まず、ソニーの開発者向けサイトからカメラリモートAPI SDKをダウンロードしておきましょう。チュートリアル、APIリファレンス、サンプルコードが同梱されています。
カメラリモートAPIの使い方の流れは以下の通りです。
それでは、これからこちらのサンプルコードを使って 「リモートで動画撮影の開始・終了を行う」 ところまで説明していきます。言語はRubyを使いますので、環境の無い方は公式サイトなどを参考にインストールしてください。バージョンは2.2.3で動作確認しましたが、おそらく1.9.3以上なら動くと思います。
1. PCとカメラをWi-Fi接続する
まずはこちらの方法でアクションカムのSSIDとパスワードを調べ、PCからアクションカムにWi-Fi接続します。
GUIのメニューから設定してもOKですが、自作プログラムに組み込むことを考慮するとスクリプト化しておくのが理想です。Linux用(Raspberry Pi対応)、Mac用を用意しましたので、良かったら使ってみてください。下記のようにコマンドラインから接続できます。
$ bash wificonn_linux.sh <interface-name> <network-SSID> <password>
$ bash wificonn_mac.sh <network-SSID> <password>
2. SSDPでカメラのデバイス情報を取得する
SSDPとは、同一ネットワーク上にあるUPnP対応デバイスの検索を行うための規格です。詳しくはこのサイトの説明がわかりやすくて参考になります。
RubyではfriskyというgemをインストールすればSSDPを使えるようになります。
ついでにhttpclientとnokogiriも入れておきましょう。
$ gem install frisky httpclient nokogiri
まず、以下のようにしてSSDPでデバイス検索を行います。
require 'frisky/ssdp'
require 'httpclient'
require 'nokogiri'
require 'json'
require 'pp'
# SSDPで所定のデバイスを検索
SSDP_SEARCH_TARGET = 'urn:schemas-sony-com:service:ScalarWebAPI:1'
SSDP_SEARCH_RETRY = 3
SSDP_RETRY_INTERVAL = 5
try = 1
while true do
response = Frisky::SSDP.search SSDP_SEARCH_TARGET
if ! response.empty?
break
elsif try < SSDP_SEARCH_RETRY
try += 1
puts "SSDP discover failed, retrying... (#{try}/#{SSDP_SEARCH_RETRY})"
sleep(SSDP_RETRY_INTERVAL)
else
puts "The device not found."
exit 3
end
end
pp response
puts 'SSDP discover succeeded.'
デバイス検索は一回だけだと失敗することもあるので、念のため何度かリトライしてやります。
Frisky::SSDP.search
メソッドの引数は検索ターゲットで、カメラリモートAPI特有の文字列を指定してやります。何も指定しない場合は同一ネットワークの全てのデバイスが得られます。
これを実行するとアクションカムより以下のようなレスポンスが返ってきます。
[{:cache_control=>"max-age=1800",
:ext=>"",
:location=>"http://192.168.122.1:64321/dd.xml",
:server=>"UPnP/1.0 MINT-X/1.8.1",
:st=>"urn:schemas-sony-com:service:ScalarWebAPI:1",
:usn=>
"uuid:000000001000-1010-8000-FEC2DEEB77DC::urn:schemas-sony-com:service:ScalarWebAPI:1"}]
最も重要なのは:location
をキーとするhttp://192.168.122.1:64321/dd.xml
です。
このdd.xmlはデバイスデスクリプションというもので、カメラリモートAPIを利用するために必要な情報が書かれています。これをHTTP GETで取得し、nokogiriを使ってパースしてやります。
# デバイスデスクリプション解析
dd_xml = Nokogiri::XML(dd)
if dd_xml.nil?
puts 'Failed to parse XML.'
exit 1
end
dd_xml.remove_namespaces!
camera_name = dd_xml.css('device friendlyName')
services = dd_xml.css('device X_ScalarWebAPI_Service')
endpoint_urls = {}
services.each do |sv|
service_type = sv.css('X_ScalarWebAPI_ServiceType').inner_text
endpoint_urls[service_type] = File.join(sv.css('X_ScalarWebAPI_ActionList_URL').inner_text, service_type)
end
puts 'Endpoint URLs are:'
pp endpoint_urls
デバイスデスクリプションを取得すると、中身はこのようなXMLになっています。
特に重要なエレメントはX_ScalarWebAPI_ServiceType
とX_ScalarWebAPI_ActionList_URL
です。
ServiceTypeはカメラリモートAPI群の分類で、以下の様なものがあります。
種別 | 説明 |
---|---|
guide | サポートするAPIサービスの取得 |
camera | カメラ設定の取得変更、および撮影機能へのアクセス(最も使う) |
system | システム設定の取得変更 |
avContent | メディアに記録された静止画・動画へのアクセス |
ServiceTypeと対応するActionList_URLを/
で繋げて<ActionList_URL>/<ServiceType>
とすると、次節で使用する エンドポイントURL になります。
先ほどのコードを実行すると、以下のようにサービスタイプをキーとしたエンドポイントURLの連想配列が得られます。
Endpoint URLs are:
{"guide"=>"http://192.168.122.1:8080/sony/guide",
"accessControl"=>"http://192.168.122.1:8080/sony/accessControl",
"camera"=>"http://192.168.122.1:8080/sony/camera",
"system"=>"http://192.168.122.1:8080/sony/system",
"avContent"=>"http://192.168.122.1:8080/sony/avContent"}
デバイス検索に失敗する場合は
SSDPはブロードキャストアドレスとして239.255.255.250
のアドレスを使用しますが、ホストが複数のネットワークに接続している場合、ルーティングに問題がある可能性があります。仮に、ホストがwlan0で家庭内LANに接続し、wlan1でアクションカムに接続しているとしましょう。
239.255.255.250
へのルートを調べるには、ip route get
コマンドを使用します。
$ ip route get 239.255.255.250
multicast 239.255.255.250 dev wlan0 src 192.168.1.10
cache <mc>
このように dev wlan0 と表示された場合、239.255.255.250
にはwlan0を介した経路が設定されているため、デバイス検索はwlan0の接続しているネットワーク(家庭内LAN)内で行われます。そのため、wlan1のネットワークに接続しているアクションカムはSSDPの検索にヒットしなくなってしまいます。
wlan1を介した経路を追加するには、route add
コマンドを使用します。
$ sudo route add -host 239.255.255.250 dev wlan1
再度ip route get
コマンドを実行して、 dev wlan1 と表示されていればOKです。
こちらもスクリプトを用意しましたので、困ったら活用してください。
3. カメラにJSON-RPCでコマンドを送信する
JSON-RPCとはJSONを用いてリモートプロシージャコールを行う規格で、カメラリモートAPIの呼び出しにはこのJSON-RPCを使用します。
決められたフォーマットでJSONデータを作成し、前節で調べたエンドポイントURLに対してHTTP POSTを実行することでAPIの呼び出しが可能です。JSONデータのフォーマットは以下のように定められています。
キー | 値 |
---|---|
method | 呼びだすAPIの名前 |
params | APIに渡すパラメータの連想配列 |
id | ユーザーがAPI呼び出しの識別に利用できる番号 |
version | APIのバージョン |
APIリファレンスによると、例えば "setShootMode" APIを用いて撮影モードを動画撮影に切り替えるJSONは以下のように書けます。静止画撮影やインターバル静止画撮影モードにするなら、paramsに渡す文字列をそれぞれ"still"
, "intervalstill"
というように変えてやります。
{
"method": "setShootMode",
"params": ["movie"],
"id": 1,
"version": "1.0"
}
"setShootMode" APIのサービスタイプは"camera"なので、エンドポイントURLはhttp://192.168.122.1:8080/sony/camera
となります。このアドレスに対し上記のJSONをPOSTすると、アクションカムのリモート手続完了後にレスポンスのJSONが返され、実行結果を確認することができます。
たいていのAPIは成功時に"result"キーと0の値のペアを返しますが、エラーの際には"result"は返されず、代わりに”error"キーとエラーコード・メッセージの値が返ってきます。
{
"result": [0],
"id": 1
}
{
"error": [2, "Timeout"],
"id": 1
}
それでは、"setShootMode"に加えて"startMovieRec"と”stopMovieRec"という3つのAPIを使って、録画の開始・停止を実行してみます。"id"キーの値はAPIの実行順ごとに連番にしていますが、単純に同じ値を使っても大丈夫です。
setShootMode_request = {
'method' => 'setShootMode',
'params' => ['movie'],
'id' => 1,
'version' => '1.0'
}
startMovieRec_request = {
'method' => 'startMovieRec',
'params' => [],
'id' => 2,
'version' => '1.0'
}
stopMovieRec_request = {
'method' => 'stopMovieRec',
'params' => [],
'id' => 3,
'version' => '1.0'
}
# 撮影モード切り替え->録画開始->録画停止
res = cli.post_content(endpoint_urls['camera'], setShootMode_request.to_json)
pp JSON.parse(res)
res = cli.post_content(endpoint_urls['camera'], startMovieRec_request.to_json)
pp JSON.parse(res)
sleep(5)
res = cli.post_content(endpoint_urls['camera'], stopMovieRec_request.to_json)
pp JSON.parse(res)
実行すると、録画が始まって5秒間経過したのち停止します。画面には下記のような出力が出て、APIが正常に終了したことを確認できます(stopMovieRecは、現状では成功時に空文字列を返すようです)。
{"result"=>[0], "id"=>1}
{"result"=>[0], "id"=>2}
{"result"=>[""], "id"=>3}
終わりに
今回はソニーのカメラリモートAPIを利用して、PCから録画の開始・終了を実行してみました。
他にも、静止画撮影や撮影したコンテンツの取得、ライブビューの取得など、やれることは様々です。
今後も機会がありましたら解説記事を上げていこうと思います。
ちなみに、CanonやNikon、GoProも同様のAPIを公開しています。こちらの製品をお持ちの方は、是非トライしてみてください。