Skip to content

Commit

Permalink
Merge branch 'release/0.1.0'
Browse files Browse the repository at this point in the history
* release/0.1.0:
  Update readme & abstract local file creation
  (GH-6) Add xml documentation to public members * fixes #6
  (GH-3) Add Set/Get Date, Take picture sets date * fixes #3
  (GH-4) Reduce external dependencies * fixes #4
  Add TakePicture support for local uri
  Inital PoC
  • Loading branch information
devlead committed Sep 25, 2019
2 parents a45f0e8 + 1b2a9b4 commit 97a3021
Show file tree
Hide file tree
Showing 37 changed files with 5,075 additions and 1 deletion.
79 changes: 78 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,79 @@
# OSC.Net
.NET Standard Library for Open Spherical Camera API
.NET Standard Library for Open Spherical Camera API 2.0

## Example
```csharp
var cameraClient = new CameraClient();
cameraClient.TakePicture("test.jpg");
```

## Client

The library exposes `CameraClient` class which implements an `ICameraClient` interface, which has a set of extension methods on it i.e. `TakePicture()`.

### Create client default IP (192.168.42.1) and Port (80)
```csharp
var cameraClient = new CameraClient();
```

### Create client supply IP and Port
```csharp
var cameraClient = new CameraClient(new IPEndPoint(IPAddress.Parse("192.168.42.1"), 80));
```

### Create client supply Uri
```csharp
var cameraClient = new CameraClient(new Uri("http://192.168.42.1"));
```

### HttpClientFactoryHandler

All `CameraClient` constructors takes an optional `HttpClientFactoryHandler` `createClient`parameter which allows you to override how the internally used HttpClient is created.

Example usage with `System.Net` `IHttpClientFactory`
```csharp
var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider();
var httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();

var httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();

var cameraClient = new CameraClient(createClient: httpClientFactory.CreateClient);
```

### CreateFileHandler

All `CameraClient` constructors takes an optional `CreateFileHandler` `createFile`parameter which allows you to override how local files are created.

```csharp
var cameraClient = new CameraClient(
createFile: path => File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None));
```

## Take Picture

### Take picture and get uri to image

```csharp
var pictureUri = await client.TakePicture();
```

### Take picture and download image to supplied stream

```csharp
var imageStream = new MemoryStream();
await client.TakePicture(imageStream);
```

### Take picture and save to supplied local path
```csharp
await client.TakePicture("test.jpg");
```

### useLocalFileUri

All `TakePicture` methods takes an optional `useLocalFileUri` bool parameter, by default it's false. If set to true it'll use `ICameraClient.EndPoint` for construction an absolute uri to images. This is useful if using camera through proxy or firewall.

## Supported cameras

This library has been tested with
* [Insta360 One X](https://www.insta360.com/product/insta360-onex/)
17 changes: 17 additions & 0 deletions src/OSC.Net.Console/OSC.Net.Console.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="3.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\OSC.Net\OSC.Net.csproj" />
</ItemGroup>

</Project>
51 changes: 51 additions & 0 deletions src/OSC.Net.Console/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.IO;
using System.Net.Http;
using static System.Console;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using OSC.Net.Model;

namespace OSC.Net.Console
{
public static class Program
{
public static async Task Main(string[] args)
{
var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider();
var httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();


var client = Uri.TryCreate(
Environment.GetEnvironmentVariable("OSC.Net.Console.EndPoint"),
UriKind.Absolute,
out var endpoint)
? new CameraClient(endpoint, createClient: httpClientFactory.CreateClient)
: new CameraClient(createClient: httpClientFactory.CreateClient);


var currentDateTime = await client.GetDateTime();
WriteLine(currentDateTime);

await client.SetDateTime(DateTimeOffset.Now);

currentDateTime = await client.GetDateTime();
WriteLine(currentDateTime);

var pictureUri = await client.TakePicture(true);
WriteLine("PictureUri: {0}", pictureUri);

var imageStream = new MemoryStream();
await client.TakePicture(imageStream, true);
WriteLine("Downloaded {0} bytes.", imageStream.Length);

await client.TakePicture("test.jpg", true);
WriteLine("test.jpg {0}.", File.Exists("test.jpg") ? "exists" : "missing");

var captureMode = await client.GetCaptureMode();
WriteLine("CaptureMode: {0}", captureMode);

await client.SetCaptureMode(CaptureMode.image);
}
}
}
31 changes: 31 additions & 0 deletions src/OSC.Net.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29318.209
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OSC.Net", "OSC.Net\OSC.Net.csproj", "{ADCC92AF-67AA-460C-B3D5-A20931C0A3E6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSC.Net.Console", "OSC.Net.Console\OSC.Net.Console.csproj", "{B9E66C20-2458-45E4-B811-40D9EAAD4F99}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ADCC92AF-67AA-460C-B3D5-A20931C0A3E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADCC92AF-67AA-460C-B3D5-A20931C0A3E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADCC92AF-67AA-460C-B3D5-A20931C0A3E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADCC92AF-67AA-460C-B3D5-A20931C0A3E6}.Release|Any CPU.Build.0 = Release|Any CPU
{B9E66C20-2458-45E4-B811-40D9EAAD4F99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9E66C20-2458-45E4-B811-40D9EAAD4F99}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9E66C20-2458-45E4-B811-40D9EAAD4F99}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9E66C20-2458-45E4-B811-40D9EAAD4F99}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {98743999-18AB-4A71-AFE8-E57844A2F6EB}
EndGlobalSection
EndGlobal
87 changes: 87 additions & 0 deletions src/OSC.Net/CameraClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using OSC.Net.Http;
using OSC.Net.IO;

namespace OSC.Net
{
/// <summary>
/// Standard implementation of <see cref="ICameraClient"/>.
/// </summary>
public class CameraClient : ICameraClient
{
private static Stream DefaultCreateFile(string path)
=> File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);

private static HttpClient DefaultCreateClient(string name) => new HttpClient();

/// <summary>
/// The Default Camera Ip Address.
/// </summary>
/// <value>192.168.42.1</value>
public const string DefaultIp = "192.168.42.1";

/// <summary>
/// The Default Camera Port.
/// </summary>
/// <value>80</value>
public const int DefaultPort = 80;

/// <summary>
/// The Default Camera ip end point.
/// </summary>
/// <value>192.168.42.1:80</value>
public static readonly IPEndPoint DefaultIpEndPoint = new IPEndPoint(IPAddress.Parse(DefaultIp), DefaultPort);

private HttpClientFactoryHandler CreateClient { get; }
private CreateFileHandler CreateFile { get; }

/// <inheritdoc />
public Uri EndPoint { get; }

/// <inheritdoc />
HttpClient ICameraClient.GetHttpClient()
{
var client = CreateClient(nameof(CameraClient));
client.BaseAddress = EndPoint;
return client;
}

/// <inheritdoc />
Stream ICameraClient.CreateFile(string path) => CreateFile(path);

/// <summary>
/// Initializes a new instance of the <see cref="CameraClient"/> class using <see cref="DefaultIpEndPoint"/>.
/// </summary>
/// <param name="createFile">Optional handler to override local file creation.</param>
/// <param name="createClient">Optional handler to override http client creation.</param>
public CameraClient(CreateFileHandler createFile = null, HttpClientFactoryHandler createClient = null) : this(DefaultIpEndPoint, createFile, createClient)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="CameraClient"/> class.
/// </summary>
/// <param name="ipEndPoint">The camera ip address and port.</param>
/// <param name="createFile">Optional handler to override local file creation.</param>
/// <param name="createClient">Optional handler to override http client creation.</param>
public CameraClient(IPEndPoint ipEndPoint, CreateFileHandler createFile = null, HttpClientFactoryHandler createClient = null) : this(new Uri($"http://{ipEndPoint}"), createFile, createClient)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="CameraClient"/> class.
/// </summary>
/// <param name="endPoint">The camera http end point.</param>
/// <param name="createFile">Optional handler to override local file creation.</param>
/// <param name="createClient">Optional handler to override http client creation.</param>
public CameraClient(Uri endPoint, CreateFileHandler createFile = null, HttpClientFactoryHandler createClient = null)
{
EndPoint = endPoint;
CreateFile = createFile ?? DefaultCreateFile;
CreateClient = createClient ?? DefaultCreateClient;
}
}
}
74 changes: 74 additions & 0 deletions src/OSC.Net/Commands.CaptureMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Threading.Tasks;
using OSC.Net.Model;
using OSC.Net.Model.SetOptions;

namespace OSC.Net
{
public static partial class Commands
{
/// <summary>
/// Gets camera current capture mode.
/// </summary>
/// <param name="client">The <see cref="ICameraClient"/> method extends.</param>
/// <returns>Current <see cref="CaptureMode"/>.</returns>
public static async Task<CaptureMode> GetCaptureMode(this ICameraClient client)
{
var result = await client.PostAsJson<Model.GetOptions.Result<Model.GetCaptureMode.Options>>(new
{
name = "camera.getOptions",
parameters = new
{
optionNames = new[]
{
"captureMode"
}
}
});

return Enum.TryParse(result?.results?.options?.captureMode, true, out CaptureMode mode)
? mode
: CaptureMode.unknown;
}

/// <summary>
/// Sets camera capture mode.
/// </summary>
/// <param name="client">The <see cref="ICameraClient"/> method extends.</param>
/// <param name="captureMode">Supported capture modes <see cref="CaptureMode.image"/> and <see cref="CaptureMode.video"/>.</param>
/// <returns></returns>
public static async Task SetCaptureMode(this ICameraClient client, CaptureMode captureMode)
{
switch (captureMode)
{
case CaptureMode.image:
case CaptureMode.video:
break;

// ReSharper disable once RedundantCaseLabel
case CaptureMode._other:
// ReSharper disable once RedundantCaseLabel
case CaptureMode.unknown:
default:
throw new ArgumentOutOfRangeException(nameof(captureMode), captureMode, null);
}

var result = await client.PostAsJson<Result>(new
{
name = "camera.setOptions",
parameters = new
{
options = new
{
captureMode = captureMode.ToString("F")
}
}
});

if (result?.error != null)
{
throw new Exception($"Failed to set options (code: {result.error.code}, message: {result.error.message}).");
}
}
}
}
Loading

0 comments on commit 97a3021

Please sign in to comment.