Skip to content
This repository has been archived by the owner on Aug 25, 2021. It is now read-only.

Commit

Permalink
Implement basic Dart FFI bindings for Jason API (#194, #182)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlapa authored Apr 20, 2021
1 parent 663a294 commit 44e5aaf
Show file tree
Hide file tree
Showing 39 changed files with 1,643 additions and 16 deletions.
89 changes: 87 additions & 2 deletions jason/flutter/example/integration_test/jason.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,96 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:medea_jason/audio_track_constraints.dart';
import 'package:medea_jason/jason.dart';
import 'package:medea_jason/kind.dart';
import 'package:medea_jason/device_video_track_constraints.dart';
import 'package:medea_jason/media_stream_settings.dart';
import 'package:medea_jason/display_video_track_constraints.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

testWidgets('add test', (WidgetTester tester) async {
expect(add(2, 2), equals(4));
// testWidgets('Jason', (WidgetTester tester) async {
// var jason = Jason();
// var room = jason.initRoom();
//
// expect(() => jason.mediaManager(), returnsNormally);
// expect(() => jason.closeRoom(room), returnsNormally);
// expect(() => jason.closeRoom(room), throwsStateError);
// });

testWidgets('MediaManager', (WidgetTester tester) async {
var jason = Jason();
var mediaManager = jason.mediaManager();

var devices = mediaManager.enumerateDevices();
var tracks = mediaManager.initLocalTracks(MediaStreamSettings());

expect(devices.length, equals(3));
expect(tracks.length, equals(3));

expect(devices.first.ptr.getInnerPtr(),
isNot(equals(devices.last.ptr.getInnerPtr())));
expect(tracks.first.ptr.getInnerPtr(),
isNot(equals(tracks.last.ptr.getInnerPtr())));

expect(devices.first.deviceId(), equals('InputDeviceInfo.device_id'));
expect(devices.first.groupId(), equals('InputDeviceInfo.group_id'));
expect(devices.first.kind(), equals(MediaKind.Audio));
expect(devices.first.label(), equals('InputDeviceInfo.label'));

devices.first.free();
expect(() => devices.first.label(), throwsStateError);

expect(tracks.first.kind(), equals(MediaKind.Video));
expect(tracks.first.mediaSourceKind(), equals(MediaSourceKind.Display));

tracks.first.free();
expect(() => tracks.first.kind(), throwsStateError);
});

testWidgets('DeviceVideoTrackConstraints', (WidgetTester tester) async {
var constraints = DeviceVideoTrackConstraints();
constraints.deviceId('deviceId');
constraints.exactFacingMode(FacingMode.User);
constraints.idealFacingMode(FacingMode.Right);
constraints.exactHeight(444);
constraints.idealHeight(111);
constraints.heightInRange(55, 66);
constraints.exactWidth(444);
constraints.idealWidth(111);
constraints.widthInRange(55, 66);
constraints.free();
expect(() => constraints.deviceId('deviceId'), throwsStateError);

var constraints2 = DeviceVideoTrackConstraints();
var settings = MediaStreamSettings();
constraints2.deviceId('deviceId');
settings.deviceVideo(constraints2);
expect(() => constraints2.deviceId('deviceId'), throwsStateError);
});

testWidgets('DisplayVideoTrackConstraints', (WidgetTester tester) async {
var constraints = DisplayVideoTrackConstraints();
constraints.free();
expect(() => constraints.free(), throwsStateError);

var constraints2 = DisplayVideoTrackConstraints();
var settings = MediaStreamSettings();
settings.displayVideo(constraints2);
expect(() => settings.displayVideo(constraints2), throwsStateError);
});

testWidgets('AudioTrackConstraints', (WidgetTester tester) async {
var constraints = AudioTrackConstraints();
constraints.deviceId('deviceId');
constraints.free();
expect(() => constraints.deviceId('deviceId'), throwsStateError);

var constraints2 = AudioTrackConstraints();
var settings = MediaStreamSettings();
constraints2.deviceId('deviceId');
settings.audio(constraints2);
expect(() => constraints2.deviceId('deviceId'), throwsStateError);
});
}
6 changes: 1 addition & 5 deletions jason/flutter/example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:medea_jason/jason.dart';

void main() {
runApp(MyApp());
Expand All @@ -11,12 +10,9 @@ class MyApp extends StatefulWidget {
}

class _MyAppState extends State<MyApp> {
int _sum = 0;

@override
void initState() {
super.initState();
_sum = add(2, 2);
}

@override
Expand All @@ -27,7 +23,7 @@ class _MyAppState extends State<MyApp> {
title: const Text('Plugin example app'),
),
body: Center(
child: Text('2 + 2 = $_sum\n'),
child: Text(''),
),
),
);
Expand Down
42 changes: 42 additions & 0 deletions jason/flutter/lib/audio_track_constraints.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';

import 'jason.dart';
import 'util/move_semantic.dart';
import 'util/nullable_pointer.dart';

typedef _new_C = Pointer Function();
typedef _new_Dart = Pointer Function();

typedef _deviceId_C = Void Function(Pointer, Pointer<Utf8>);
typedef _deviceId_Dart = void Function(Pointer, Pointer<Utf8>);

typedef _free_C = Void Function(Pointer);
typedef _free_Dart = void Function(Pointer);

final _new = dl.lookupFunction<_new_C, _new_Dart>('AudioTrackConstraints__new');

final _deviceId = dl.lookupFunction<_deviceId_C, _deviceId_Dart>(
'AudioTrackConstraints__device_id');

final _free =
dl.lookupFunction<_free_C, _free_Dart>('AudioTrackConstraints__free');

class AudioTrackConstraints {
final NullablePointer ptr = NullablePointer(_new());

void deviceId(String deviceId) {
var deviceIdPtr = deviceId.toNativeUtf8();
try {
_deviceId(ptr.getInnerPtr(), deviceIdPtr);
} finally {
calloc.free(deviceIdPtr);
}
}

@moveSemantics
void free() {
_free(ptr.getInnerPtr());
ptr.free();
}
}
36 changes: 36 additions & 0 deletions jason/flutter/lib/connection_handle.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import 'dart:ffi';

import 'package:ffi/ffi.dart';

import 'jason.dart';
import 'util/move_semantic.dart';
import 'util/native_string.dart';
import 'util/nullable_pointer.dart';

typedef _getRemoteMemberId_C = Pointer<Utf8> Function(Pointer);
typedef _getRemoteMemberId_Dart = Pointer<Utf8> Function(Pointer);

typedef _free_C = Void Function(Pointer);
typedef _free_Dart = void Function(Pointer);

final _getRemoteMemberId =
dl.lookupFunction<_getRemoteMemberId_C, _getRemoteMemberId_Dart>(
'ConnectionHandle__get_remote_member_id');

final _free = dl.lookupFunction<_free_C, _free_Dart>('ConnectionHandle__free');

class ConnectionHandle {
late NullablePointer ptr;

ConnectionHandle(this.ptr);

String getRemoteMemberId() {
return _getRemoteMemberId(ptr.getInnerPtr()).nativeStringToDartString();
}

@moveSemantics
void free() {
_free(ptr.getInnerPtr());
ptr.free();
}
}
132 changes: 132 additions & 0 deletions jason/flutter/lib/device_video_track_constraints.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';

import 'jason.dart';
import 'util/move_semantic.dart';
import 'util/nullable_pointer.dart';

typedef _new_C = Pointer Function();
typedef _new_Dart = Pointer Function();

typedef _deviceId_C = Void Function(Pointer, Pointer<Utf8>);
typedef _deviceId_Dart = void Function(Pointer, Pointer<Utf8>);

typedef _exactFacingMode_C = Void Function(Pointer, Uint8);
typedef _exactFacingMode_Dart = void Function(Pointer, int);

typedef _idealFacingMode_C = Void Function(Pointer, Uint8);
typedef _idealFacingMode_Dart = void Function(Pointer, int);

typedef _exactHeight_C = Void Function(Pointer, Uint32);
typedef _exactHeight_Dart = void Function(Pointer, int);

typedef _idealHeight_C = Void Function(Pointer, Uint32);
typedef _idealHeight_Dart = void Function(Pointer, int);

typedef _heightInRange_C = Void Function(Pointer, Uint32, Uint32);
typedef _heightInRange_Dart = void Function(Pointer, int, int);

typedef _exactWidth_C = Void Function(Pointer, Uint32);
typedef _exactWidth_Dart = void Function(Pointer, int);

typedef _idealWidth_C = Void Function(Pointer, Uint32);
typedef _idealWidth_Dart = void Function(Pointer, int);

typedef _widthInRange_C = Void Function(Pointer, Uint32, Uint32);
typedef _widthInRange_Dart = void Function(Pointer, int, int);

typedef _free_C = Void Function(Pointer);
typedef _free_Dart = void Function(Pointer);

final _new =
dl.lookupFunction<_new_C, _new_Dart>('DeviceVideoTrackConstraints__new');

final _deviceId = dl.lookupFunction<_deviceId_C, _deviceId_Dart>(
'DeviceVideoTrackConstraints__device_id');

final _exactFacingMode =
dl.lookupFunction<_exactFacingMode_C, _exactFacingMode_Dart>(
'DeviceVideoTrackConstraints__exact_facing_mode');

final _idealFacingMode =
dl.lookupFunction<_idealFacingMode_C, _idealFacingMode_Dart>(
'DeviceVideoTrackConstraints__ideal_facing_mode');

final _exactHeight = dl.lookupFunction<_exactHeight_C, _exactHeight_Dart>(
'DeviceVideoTrackConstraints__exact_height');

final _idealHeight = dl.lookupFunction<_idealHeight_C, _idealHeight_Dart>(
'DeviceVideoTrackConstraints__ideal_height');

final _heightInRange = dl.lookupFunction<_heightInRange_C, _heightInRange_Dart>(
'DeviceVideoTrackConstraints__height_in_range');

final _exactWidth = dl.lookupFunction<_exactWidth_C, _exactWidth_Dart>(
'DeviceVideoTrackConstraints__exact_width');

final _idealWidth = dl.lookupFunction<_idealWidth_C, _idealWidth_Dart>(
'DeviceVideoTrackConstraints__ideal_width');

final _widthInRange = dl.lookupFunction<_widthInRange_C, _widthInRange_Dart>(
'DeviceVideoTrackConstraints__width_in_range');

final _free =
dl.lookupFunction<_free_C, _free_Dart>('DeviceVideoTrackConstraints__free');

enum FacingMode {
User,
Environment,
Left,
Right,
}

class DeviceVideoTrackConstraints {
final NullablePointer ptr = NullablePointer(_new());

void deviceId(String deviceId) {
var deviceIdPtr = deviceId.toNativeUtf8();
try {
_deviceId(ptr.getInnerPtr(), deviceIdPtr);
} finally {
calloc.free(deviceIdPtr);
}
}

void exactFacingMode(FacingMode facingMode) {
_exactFacingMode(ptr.getInnerPtr(), facingMode.index);
}

void idealFacingMode(FacingMode facingMode) {
_idealFacingMode(ptr.getInnerPtr(), facingMode.index);
}

void exactHeight(int height) {
_exactHeight(ptr.getInnerPtr(), height);
}

void idealHeight(int height) {
_idealHeight(ptr.getInnerPtr(), height);
}

void heightInRange(int min, int max) {
_heightInRange(ptr.getInnerPtr(), min, max);
}

void exactWidth(int width) {
_exactWidth(ptr.getInnerPtr(), width);
}

void idealWidth(int width) {
_idealWidth(ptr.getInnerPtr(), width);
}

void widthInRange(int min, int max) {
_widthInRange(ptr.getInnerPtr(), min, max);
}

@moveSemantics
void free() {
_free(ptr.getInnerPtr());
ptr.free();
}
}
27 changes: 27 additions & 0 deletions jason/flutter/lib/display_video_track_constraints.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'dart:ffi';

import 'jason.dart';
import 'util/move_semantic.dart';
import 'util/nullable_pointer.dart';

typedef _new_C = Pointer Function();
typedef _new_Dart = Pointer Function();

typedef _free_C = Void Function(Pointer);
typedef _free_Dart = void Function(Pointer);

final _new =
dl.lookupFunction<_new_C, _new_Dart>('DisplayVideoTrackConstraints__new');

final _free_Dart _free = dl
.lookupFunction<_free_C, _free_Dart>('DisplayVideoTrackConstraints__free');

class DisplayVideoTrackConstraints {
final NullablePointer ptr = NullablePointer(_new());

@moveSemantics
void free() {
_free(ptr.getInnerPtr());
ptr.free();
}
}
Loading

0 comments on commit 44e5aaf

Please sign in to comment.