add: basic webrtc is working
This commit is contained in:
+145
-25
@@ -1,22 +1,60 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||
import 'package:grpc/grpc.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:ui/gen/signaler_service.pb.dart';
|
||||
import 'package:ui/gen/signaler_service.pbgrpc.dart' as pb;
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:ui/session_service.dart';
|
||||
|
||||
class Call extends StatefulWidget {
|
||||
final String host;
|
||||
const Call({required this.host, super.key});
|
||||
final pb.SignalerServiceClient client;
|
||||
final SessionService sessionService;
|
||||
final pb.Camera_Identifier cameraID;
|
||||
final String home;
|
||||
const Call(this.client, this.sessionService,
|
||||
{required this.cameraID, required this.home, super.key});
|
||||
|
||||
@override
|
||||
_CallState createState() => _CallState();
|
||||
CallState createState() => CallState();
|
||||
}
|
||||
|
||||
class _CallState extends State<Call> {
|
||||
class CallState extends State<Call> {
|
||||
Logger logger = Logger();
|
||||
RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();
|
||||
final RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();
|
||||
bool _ready = false;
|
||||
String statusLine = "Building...";
|
||||
|
||||
void _connect(BuildContext context) async {}
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
_connect();
|
||||
}
|
||||
|
||||
Future<Session> _createSesson() async {
|
||||
_connect() async {
|
||||
_ready = false;
|
||||
logger.i("Init remote renderer");
|
||||
await _remoteRenderer.initialize();
|
||||
logger.i("Creating session");
|
||||
await _createSesson();
|
||||
}
|
||||
|
||||
_createSesson() async {
|
||||
var callOptions = CallOptions(metadata: {
|
||||
'Authorization': await widget.sessionService.getAuthToken(widget.home)
|
||||
});
|
||||
|
||||
var cancelCreate = Completer();
|
||||
|
||||
var clientSession = await widget.client.createSession(
|
||||
pb.CreateSessionRequest(
|
||||
session: pb.Session(
|
||||
camera: widget.cameraID,
|
||||
),
|
||||
),
|
||||
options: callOptions);
|
||||
RTCPeerConnection peerConnection = await createPeerConnection({
|
||||
// Ice servers; just use the Google one for now
|
||||
'iceServers': [
|
||||
@@ -28,47 +66,129 @@ class _CallState extends State<Call> {
|
||||
|
||||
peerConnection.onAddStream = (stream) {
|
||||
// Stream has been added; connect it to our renderer
|
||||
logger.i("Got stream from remote; connecting it");
|
||||
_remoteRenderer.srcObject = stream;
|
||||
_ready = true;
|
||||
setState(() {});
|
||||
};
|
||||
|
||||
peerConnection.onIceCandidate = (candidate) {
|
||||
peerConnection.onIceCandidate = (candidate) async {
|
||||
if (candidate.candidate == null) {
|
||||
logger.i("Out of candidates");
|
||||
await widget.client.createIceMessage(
|
||||
CreateIceMessageRequest(
|
||||
sessionIdentifier: clientSession.id,
|
||||
iceMessage: IceMessage(
|
||||
noMoreCandidates: NoMoreCandidates(),
|
||||
)),
|
||||
options: callOptions);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the candidate on to the signaling server
|
||||
await widget.client.createIceMessage(
|
||||
pb.CreateIceMessageRequest(
|
||||
sessionIdentifier: clientSession.id,
|
||||
iceMessage: pb.IceMessage(
|
||||
candidate: pb.IceCandidate(
|
||||
candidate: candidate.candidate,
|
||||
sdpMid: candidate.sdpMid,
|
||||
sdpLineIndex: candidate.sdpMLineIndex,
|
||||
),
|
||||
),
|
||||
),
|
||||
options: callOptions);
|
||||
};
|
||||
|
||||
peerConnection.onIceConnectionState = (state) {};
|
||||
peerConnection.onIceConnectionState = (state) {
|
||||
statusLine = "Ice state now $state";
|
||||
setState(() {});
|
||||
logger.i("Ice state now $state");
|
||||
|
||||
switch (state) {
|
||||
case RTCIceConnectionState.RTCIceConnectionStateClosed:
|
||||
case RTCIceConnectionState.RTCIceConnectionStateDisconnected:
|
||||
case RTCIceConnectionState.RTCIceConnectionStateFailed:
|
||||
cancelCreate.complete(CallCancelled());
|
||||
_connect();
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
|
||||
peerConnection.onIceGatheringState = (state) async {
|
||||
logger.i("ICE gathering state $state");
|
||||
if (state == RTCIceGatheringState.RTCIceGatheringStateComplete) {
|
||||
await widget.client.createIceMessage(
|
||||
CreateIceMessageRequest(
|
||||
sessionIdentifier: clientSession.id,
|
||||
iceMessage: IceMessage(
|
||||
noMoreCandidates: NoMoreCandidates(),
|
||||
)),
|
||||
options: callOptions);
|
||||
}
|
||||
};
|
||||
|
||||
peerConnection.onRemoveStream = (stream) {};
|
||||
|
||||
peerConnection.onDataChannel = (channel) {};
|
||||
|
||||
// Get list of candidates from signaling server
|
||||
for (final remoteCandidate in []) {
|
||||
peerConnection.addCandidate(remoteCandidate);
|
||||
}
|
||||
// This will find the intersection of my candidates and the remote,
|
||||
// then propose one to use
|
||||
var offer = peerConnection.createOffer();
|
||||
var offer = await peerConnection.createOffer();
|
||||
await peerConnection.setLocalDescription(offer);
|
||||
// Send offer through signaling server
|
||||
logger.i("Offer is $offer");
|
||||
await widget.client.createIceMessage(
|
||||
pb.CreateIceMessageRequest(
|
||||
sessionIdentifier: clientSession.id,
|
||||
iceMessage: pb.IceMessage(
|
||||
session: pb.IceSessionDescription(
|
||||
sdp: offer.sdp,
|
||||
sdpType: Int64(1), // offer
|
||||
),
|
||||
),
|
||||
),
|
||||
options: callOptions);
|
||||
|
||||
var session = Session(peerConnection);
|
||||
return session;
|
||||
// Get candidates from remote
|
||||
while (true) {
|
||||
var someResponse = await Future.any([
|
||||
widget.client.popIceMessage(
|
||||
pb.PopIceMessageRequest(sessionIdentifier: clientSession.id),
|
||||
options: callOptions),
|
||||
cancelCreate.future,
|
||||
]);
|
||||
if (someResponse is CallCancelled) {
|
||||
break;
|
||||
}
|
||||
var resp = someResponse as pb.IceMessage;
|
||||
if (resp.hasCandidate()) {
|
||||
await peerConnection.addCandidate(RTCIceCandidate(
|
||||
resp.candidate.candidate,
|
||||
resp.candidate.sdpMid,
|
||||
resp.candidate.sdpLineIndex));
|
||||
} else if (resp.hasNoMoreCandidates()) {
|
||||
logger.i("No more candidates from remote");
|
||||
} else if (resp.hasSession()) {
|
||||
var session = resp.session;
|
||||
await peerConnection
|
||||
.setRemoteDescription(RTCSessionDescription(session.sdp, "answer"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RTCVideoView(_remoteRenderer);
|
||||
return Column(children: [
|
||||
Text(widget.cameraID.id),
|
||||
Text(statusLine),
|
||||
SizedBox(
|
||||
height: 480,
|
||||
child: _ready
|
||||
? RTCVideoView(_remoteRenderer)
|
||||
: const Text("Loading...")),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class Session {
|
||||
RTCPeerConnection peerConnection;
|
||||
|
||||
Session(this.peerConnection);
|
||||
List<RTCIceCandidate> remoteCandidates = [];
|
||||
}
|
||||
class CallCancelled {}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// Generated code. Do not modify.
|
||||
// source: signaler_service.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
|
||||
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
//
|
||||
// Generated code. Do not modify.
|
||||
// source: signaler_service.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
|
||||
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
import 'dart:async' as $async;
|
||||
import 'dart:core' as $core;
|
||||
|
||||
import 'package:grpc/service_api.dart' as $grpc;
|
||||
import 'package:protobuf/protobuf.dart' as $pb;
|
||||
|
||||
import 'signaler_service.pb.dart' as $0;
|
||||
|
||||
export 'signaler_service.pb.dart';
|
||||
|
||||
@$pb.GrpcServiceName('signaler.SignalerService')
|
||||
class SignalerServiceClient extends $grpc.Client {
|
||||
static final _$createAuthToken = $grpc.ClientMethod<$0.CreateAuthTokenRequest, $0.AuthToken>(
|
||||
'/signaler.SignalerService/CreateAuthToken',
|
||||
($0.CreateAuthTokenRequest value) => value.writeToBuffer(),
|
||||
($core.List<$core.int> value) => $0.AuthToken.fromBuffer(value));
|
||||
static final _$listCameras = $grpc.ClientMethod<$0.ListCamerasRequest, $0.ListCamerasResponse>(
|
||||
'/signaler.SignalerService/ListCameras',
|
||||
($0.ListCamerasRequest value) => value.writeToBuffer(),
|
||||
($core.List<$core.int> value) => $0.ListCamerasResponse.fromBuffer(value));
|
||||
static final _$createSession = $grpc.ClientMethod<$0.CreateSessionRequest, $0.Session>(
|
||||
'/signaler.SignalerService/CreateSession',
|
||||
($0.CreateSessionRequest value) => value.writeToBuffer(),
|
||||
($core.List<$core.int> value) => $0.Session.fromBuffer(value));
|
||||
static final _$popSession = $grpc.ClientMethod<$0.PopSessionRequest, $0.Session>(
|
||||
'/signaler.SignalerService/PopSession',
|
||||
($0.PopSessionRequest value) => value.writeToBuffer(),
|
||||
($core.List<$core.int> value) => $0.Session.fromBuffer(value));
|
||||
static final _$createIceMessage = $grpc.ClientMethod<$0.CreateIceMessageRequest, $0.IceMessage>(
|
||||
'/signaler.SignalerService/CreateIceMessage',
|
||||
($0.CreateIceMessageRequest value) => value.writeToBuffer(),
|
||||
($core.List<$core.int> value) => $0.IceMessage.fromBuffer(value));
|
||||
static final _$popIceMessage = $grpc.ClientMethod<$0.PopIceMessageRequest, $0.IceMessage>(
|
||||
'/signaler.SignalerService/PopIceMessage',
|
||||
($0.PopIceMessageRequest value) => value.writeToBuffer(),
|
||||
($core.List<$core.int> value) => $0.IceMessage.fromBuffer(value));
|
||||
|
||||
SignalerServiceClient($grpc.ClientChannel channel,
|
||||
{$grpc.CallOptions? options,
|
||||
$core.Iterable<$grpc.ClientInterceptor>? interceptors})
|
||||
: super(channel, options: options,
|
||||
interceptors: interceptors);
|
||||
|
||||
$grpc.ResponseFuture<$0.AuthToken> createAuthToken($0.CreateAuthTokenRequest request, {$grpc.CallOptions? options}) {
|
||||
return $createUnaryCall(_$createAuthToken, request, options: options);
|
||||
}
|
||||
|
||||
$grpc.ResponseFuture<$0.ListCamerasResponse> listCameras($0.ListCamerasRequest request, {$grpc.CallOptions? options}) {
|
||||
return $createUnaryCall(_$listCameras, request, options: options);
|
||||
}
|
||||
|
||||
$grpc.ResponseFuture<$0.Session> createSession($0.CreateSessionRequest request, {$grpc.CallOptions? options}) {
|
||||
return $createUnaryCall(_$createSession, request, options: options);
|
||||
}
|
||||
|
||||
$grpc.ResponseFuture<$0.Session> popSession($0.PopSessionRequest request, {$grpc.CallOptions? options}) {
|
||||
return $createUnaryCall(_$popSession, request, options: options);
|
||||
}
|
||||
|
||||
$grpc.ResponseFuture<$0.IceMessage> createIceMessage($0.CreateIceMessageRequest request, {$grpc.CallOptions? options}) {
|
||||
return $createUnaryCall(_$createIceMessage, request, options: options);
|
||||
}
|
||||
|
||||
$grpc.ResponseFuture<$0.IceMessage> popIceMessage($0.PopIceMessageRequest request, {$grpc.CallOptions? options}) {
|
||||
return $createUnaryCall(_$popIceMessage, request, options: options);
|
||||
}
|
||||
}
|
||||
|
||||
@$pb.GrpcServiceName('signaler.SignalerService')
|
||||
abstract class SignalerServiceBase extends $grpc.Service {
|
||||
$core.String get $name => 'signaler.SignalerService';
|
||||
|
||||
SignalerServiceBase() {
|
||||
$addMethod($grpc.ServiceMethod<$0.CreateAuthTokenRequest, $0.AuthToken>(
|
||||
'CreateAuthToken',
|
||||
createAuthToken_Pre,
|
||||
false,
|
||||
false,
|
||||
($core.List<$core.int> value) => $0.CreateAuthTokenRequest.fromBuffer(value),
|
||||
($0.AuthToken value) => value.writeToBuffer()));
|
||||
$addMethod($grpc.ServiceMethod<$0.ListCamerasRequest, $0.ListCamerasResponse>(
|
||||
'ListCameras',
|
||||
listCameras_Pre,
|
||||
false,
|
||||
false,
|
||||
($core.List<$core.int> value) => $0.ListCamerasRequest.fromBuffer(value),
|
||||
($0.ListCamerasResponse value) => value.writeToBuffer()));
|
||||
$addMethod($grpc.ServiceMethod<$0.CreateSessionRequest, $0.Session>(
|
||||
'CreateSession',
|
||||
createSession_Pre,
|
||||
false,
|
||||
false,
|
||||
($core.List<$core.int> value) => $0.CreateSessionRequest.fromBuffer(value),
|
||||
($0.Session value) => value.writeToBuffer()));
|
||||
$addMethod($grpc.ServiceMethod<$0.PopSessionRequest, $0.Session>(
|
||||
'PopSession',
|
||||
popSession_Pre,
|
||||
false,
|
||||
false,
|
||||
($core.List<$core.int> value) => $0.PopSessionRequest.fromBuffer(value),
|
||||
($0.Session value) => value.writeToBuffer()));
|
||||
$addMethod($grpc.ServiceMethod<$0.CreateIceMessageRequest, $0.IceMessage>(
|
||||
'CreateIceMessage',
|
||||
createIceMessage_Pre,
|
||||
false,
|
||||
false,
|
||||
($core.List<$core.int> value) => $0.CreateIceMessageRequest.fromBuffer(value),
|
||||
($0.IceMessage value) => value.writeToBuffer()));
|
||||
$addMethod($grpc.ServiceMethod<$0.PopIceMessageRequest, $0.IceMessage>(
|
||||
'PopIceMessage',
|
||||
popIceMessage_Pre,
|
||||
false,
|
||||
false,
|
||||
($core.List<$core.int> value) => $0.PopIceMessageRequest.fromBuffer(value),
|
||||
($0.IceMessage value) => value.writeToBuffer()));
|
||||
}
|
||||
|
||||
$async.Future<$0.AuthToken> createAuthToken_Pre($grpc.ServiceCall call, $async.Future<$0.CreateAuthTokenRequest> request) async {
|
||||
return createAuthToken(call, await request);
|
||||
}
|
||||
|
||||
$async.Future<$0.ListCamerasResponse> listCameras_Pre($grpc.ServiceCall call, $async.Future<$0.ListCamerasRequest> request) async {
|
||||
return listCameras(call, await request);
|
||||
}
|
||||
|
||||
$async.Future<$0.Session> createSession_Pre($grpc.ServiceCall call, $async.Future<$0.CreateSessionRequest> request) async {
|
||||
return createSession(call, await request);
|
||||
}
|
||||
|
||||
$async.Future<$0.Session> popSession_Pre($grpc.ServiceCall call, $async.Future<$0.PopSessionRequest> request) async {
|
||||
return popSession(call, await request);
|
||||
}
|
||||
|
||||
$async.Future<$0.IceMessage> createIceMessage_Pre($grpc.ServiceCall call, $async.Future<$0.CreateIceMessageRequest> request) async {
|
||||
return createIceMessage(call, await request);
|
||||
}
|
||||
|
||||
$async.Future<$0.IceMessage> popIceMessage_Pre($grpc.ServiceCall call, $async.Future<$0.PopIceMessageRequest> request) async {
|
||||
return popIceMessage(call, await request);
|
||||
}
|
||||
|
||||
$async.Future<$0.AuthToken> createAuthToken($grpc.ServiceCall call, $0.CreateAuthTokenRequest request);
|
||||
$async.Future<$0.ListCamerasResponse> listCameras($grpc.ServiceCall call, $0.ListCamerasRequest request);
|
||||
$async.Future<$0.Session> createSession($grpc.ServiceCall call, $0.CreateSessionRequest request);
|
||||
$async.Future<$0.Session> popSession($grpc.ServiceCall call, $0.PopSessionRequest request);
|
||||
$async.Future<$0.IceMessage> createIceMessage($grpc.ServiceCall call, $0.CreateIceMessageRequest request);
|
||||
$async.Future<$0.IceMessage> popIceMessage($grpc.ServiceCall call, $0.PopIceMessageRequest request);
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
//
|
||||
// Generated code. Do not modify.
|
||||
// source: signaler_service.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
|
||||
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
import 'dart:convert' as $convert;
|
||||
import 'dart:core' as $core;
|
||||
import 'dart:typed_data' as $typed_data;
|
||||
|
||||
@$core.Deprecated('Use createAuthTokenRequestDescriptor instead')
|
||||
const CreateAuthTokenRequest$json = {
|
||||
'1': 'CreateAuthTokenRequest',
|
||||
'2': [
|
||||
{'1': 'home', '3': 1, '4': 1, '5': 9, '10': 'home'},
|
||||
{'1': 'camera', '3': 2, '4': 1, '5': 11, '6': '.signaler.CreateAuthTokenRequest.Camera', '9': 0, '10': 'camera'},
|
||||
{'1': 'client', '3': 3, '4': 1, '5': 11, '6': '.signaler.CreateAuthTokenRequest.Client', '9': 0, '10': 'client'},
|
||||
],
|
||||
'3': [CreateAuthTokenRequest_Camera$json, CreateAuthTokenRequest_Client$json],
|
||||
'8': [
|
||||
{'1': 'type'},
|
||||
],
|
||||
};
|
||||
|
||||
@$core.Deprecated('Use createAuthTokenRequestDescriptor instead')
|
||||
const CreateAuthTokenRequest_Camera$json = {
|
||||
'1': 'Camera',
|
||||
'2': [
|
||||
{'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
|
||||
],
|
||||
};
|
||||
|
||||
@$core.Deprecated('Use createAuthTokenRequestDescriptor instead')
|
||||
const CreateAuthTokenRequest_Client$json = {
|
||||
'1': 'Client',
|
||||
};
|
||||
|
||||
/// Descriptor for `CreateAuthTokenRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List createAuthTokenRequestDescriptor = $convert.base64Decode(
|
||||
'ChZDcmVhdGVBdXRoVG9rZW5SZXF1ZXN0EhIKBGhvbWUYASABKAlSBGhvbWUSQQoGY2FtZXJhGA'
|
||||
'IgASgLMicuc2lnbmFsZXIuQ3JlYXRlQXV0aFRva2VuUmVxdWVzdC5DYW1lcmFIAFIGY2FtZXJh'
|
||||
'EkEKBmNsaWVudBgDIAEoCzInLnNpZ25hbGVyLkNyZWF0ZUF1dGhUb2tlblJlcXVlc3QuQ2xpZW'
|
||||
'50SABSBmNsaWVudBoYCgZDYW1lcmESDgoCaWQYASABKAlSAmlkGggKBkNsaWVudEIGCgR0eXBl');
|
||||
|
||||
@$core.Deprecated('Use listCamerasRequestDescriptor instead')
|
||||
const ListCamerasRequest$json = {
|
||||
'1': 'ListCamerasRequest',
|
||||
};
|
||||
|
||||
/// Descriptor for `ListCamerasRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List listCamerasRequestDescriptor = $convert.base64Decode(
|
||||
'ChJMaXN0Q2FtZXJhc1JlcXVlc3Q=');
|
||||
|
||||
@$core.Deprecated('Use listCamerasResponseDescriptor instead')
|
||||
const ListCamerasResponse$json = {
|
||||
'1': 'ListCamerasResponse',
|
||||
'2': [
|
||||
{'1': 'cameras', '3': 1, '4': 3, '5': 11, '6': '.signaler.Camera', '10': 'cameras'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `ListCamerasResponse`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List listCamerasResponseDescriptor = $convert.base64Decode(
|
||||
'ChNMaXN0Q2FtZXJhc1Jlc3BvbnNlEioKB2NhbWVyYXMYASADKAsyEC5zaWduYWxlci5DYW1lcm'
|
||||
'FSB2NhbWVyYXM=');
|
||||
|
||||
@$core.Deprecated('Use createSessionRequestDescriptor instead')
|
||||
const CreateSessionRequest$json = {
|
||||
'1': 'CreateSessionRequest',
|
||||
'2': [
|
||||
{'1': 'session', '3': 1, '4': 1, '5': 11, '6': '.signaler.Session', '10': 'session'},
|
||||
{'1': 'wait_for_update', '3': 2, '4': 1, '5': 8, '10': 'waitForUpdate'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `CreateSessionRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List createSessionRequestDescriptor = $convert.base64Decode(
|
||||
'ChRDcmVhdGVTZXNzaW9uUmVxdWVzdBIrCgdzZXNzaW9uGAEgASgLMhEuc2lnbmFsZXIuU2Vzc2'
|
||||
'lvblIHc2Vzc2lvbhImCg93YWl0X2Zvcl91cGRhdGUYAiABKAhSDXdhaXRGb3JVcGRhdGU=');
|
||||
|
||||
@$core.Deprecated('Use popSessionRequestDescriptor instead')
|
||||
const PopSessionRequest$json = {
|
||||
'1': 'PopSessionRequest',
|
||||
'2': [
|
||||
{'1': 'session', '3': 1, '4': 1, '5': 11, '6': '.signaler.Session', '10': 'session'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `PopSessionRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List popSessionRequestDescriptor = $convert.base64Decode(
|
||||
'ChFQb3BTZXNzaW9uUmVxdWVzdBIrCgdzZXNzaW9uGAEgASgLMhEuc2lnbmFsZXIuU2Vzc2lvbl'
|
||||
'IHc2Vzc2lvbg==');
|
||||
|
||||
@$core.Deprecated('Use updateSessionRequestDescriptor instead')
|
||||
const UpdateSessionRequest$json = {
|
||||
'1': 'UpdateSessionRequest',
|
||||
'2': [
|
||||
{'1': 'session', '3': 1, '4': 1, '5': 11, '6': '.signaler.Session', '10': 'session'},
|
||||
{'1': 'wait_for_update', '3': 2, '4': 1, '5': 8, '10': 'waitForUpdate'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `UpdateSessionRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List updateSessionRequestDescriptor = $convert.base64Decode(
|
||||
'ChRVcGRhdGVTZXNzaW9uUmVxdWVzdBIrCgdzZXNzaW9uGAEgASgLMhEuc2lnbmFsZXIuU2Vzc2'
|
||||
'lvblIHc2Vzc2lvbhImCg93YWl0X2Zvcl91cGRhdGUYAiABKAhSDXdhaXRGb3JVcGRhdGU=');
|
||||
|
||||
@$core.Deprecated('Use listSessionsRequestDescriptor instead')
|
||||
const ListSessionsRequest$json = {
|
||||
'1': 'ListSessionsRequest',
|
||||
};
|
||||
|
||||
/// Descriptor for `ListSessionsRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List listSessionsRequestDescriptor = $convert.base64Decode(
|
||||
'ChNMaXN0U2Vzc2lvbnNSZXF1ZXN0');
|
||||
|
||||
@$core.Deprecated('Use listSessionsResponseDescriptor instead')
|
||||
const ListSessionsResponse$json = {
|
||||
'1': 'ListSessionsResponse',
|
||||
'2': [
|
||||
{'1': 'sessions', '3': 1, '4': 3, '5': 11, '6': '.signaler.Session', '10': 'sessions'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `ListSessionsResponse`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List listSessionsResponseDescriptor = $convert.base64Decode(
|
||||
'ChRMaXN0U2Vzc2lvbnNSZXNwb25zZRItCghzZXNzaW9ucxgBIAMoCzIRLnNpZ25hbGVyLlNlc3'
|
||||
'Npb25SCHNlc3Npb25z');
|
||||
|
||||
@$core.Deprecated('Use createIceMessageRequestDescriptor instead')
|
||||
const CreateIceMessageRequest$json = {
|
||||
'1': 'CreateIceMessageRequest',
|
||||
'2': [
|
||||
{'1': 'session_identifier', '3': 1, '4': 1, '5': 11, '6': '.signaler.Session.Identifier', '10': 'sessionIdentifier'},
|
||||
{'1': 'ice_message', '3': 2, '4': 1, '5': 11, '6': '.signaler.IceMessage', '10': 'iceMessage'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `CreateIceMessageRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List createIceMessageRequestDescriptor = $convert.base64Decode(
|
||||
'ChdDcmVhdGVJY2VNZXNzYWdlUmVxdWVzdBJLChJzZXNzaW9uX2lkZW50aWZpZXIYASABKAsyHC'
|
||||
'5zaWduYWxlci5TZXNzaW9uLklkZW50aWZpZXJSEXNlc3Npb25JZGVudGlmaWVyEjUKC2ljZV9t'
|
||||
'ZXNzYWdlGAIgASgLMhQuc2lnbmFsZXIuSWNlTWVzc2FnZVIKaWNlTWVzc2FnZQ==');
|
||||
|
||||
@$core.Deprecated('Use popIceMessageRequestDescriptor instead')
|
||||
const PopIceMessageRequest$json = {
|
||||
'1': 'PopIceMessageRequest',
|
||||
'2': [
|
||||
{'1': 'session_identifier', '3': 1, '4': 1, '5': 11, '6': '.signaler.Session.Identifier', '10': 'sessionIdentifier'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `PopIceMessageRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List popIceMessageRequestDescriptor = $convert.base64Decode(
|
||||
'ChRQb3BJY2VNZXNzYWdlUmVxdWVzdBJLChJzZXNzaW9uX2lkZW50aWZpZXIYASABKAsyHC5zaW'
|
||||
'duYWxlci5TZXNzaW9uLklkZW50aWZpZXJSEXNlc3Npb25JZGVudGlmaWVy');
|
||||
|
||||
@$core.Deprecated('Use cameraDescriptor instead')
|
||||
const Camera$json = {
|
||||
'1': 'Camera',
|
||||
'2': [
|
||||
{'1': 'identifier', '3': 1, '4': 1, '5': 11, '6': '.signaler.Camera.Identifier', '10': 'identifier'},
|
||||
],
|
||||
'3': [Camera_Identifier$json],
|
||||
};
|
||||
|
||||
@$core.Deprecated('Use cameraDescriptor instead')
|
||||
const Camera_Identifier$json = {
|
||||
'1': 'Identifier',
|
||||
'2': [
|
||||
{'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `Camera`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List cameraDescriptor = $convert.base64Decode(
|
||||
'CgZDYW1lcmESOwoKaWRlbnRpZmllchgBIAEoCzIbLnNpZ25hbGVyLkNhbWVyYS5JZGVudGlmaW'
|
||||
'VyUgppZGVudGlmaWVyGhwKCklkZW50aWZpZXISDgoCaWQYASABKAlSAmlk');
|
||||
|
||||
@$core.Deprecated('Use iceMessageDescriptor instead')
|
||||
const IceMessage$json = {
|
||||
'1': 'IceMessage',
|
||||
'2': [
|
||||
{'1': 'candidate', '3': 1, '4': 1, '5': 11, '6': '.signaler.IceCandidate', '9': 0, '10': 'candidate'},
|
||||
{'1': 'session', '3': 2, '4': 1, '5': 11, '6': '.signaler.IceSessionDescription', '9': 0, '10': 'session'},
|
||||
{'1': 'no_more_candidates', '3': 3, '4': 1, '5': 11, '6': '.signaler.NoMoreCandidates', '9': 0, '10': 'noMoreCandidates'},
|
||||
],
|
||||
'8': [
|
||||
{'1': 'type'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `IceMessage`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List iceMessageDescriptor = $convert.base64Decode(
|
||||
'CgpJY2VNZXNzYWdlEjYKCWNhbmRpZGF0ZRgBIAEoCzIWLnNpZ25hbGVyLkljZUNhbmRpZGF0ZU'
|
||||
'gAUgljYW5kaWRhdGUSOwoHc2Vzc2lvbhgCIAEoCzIfLnNpZ25hbGVyLkljZVNlc3Npb25EZXNj'
|
||||
'cmlwdGlvbkgAUgdzZXNzaW9uEkoKEm5vX21vcmVfY2FuZGlkYXRlcxgDIAEoCzIaLnNpZ25hbG'
|
||||
'VyLk5vTW9yZUNhbmRpZGF0ZXNIAFIQbm9Nb3JlQ2FuZGlkYXRlc0IGCgR0eXBl');
|
||||
|
||||
@$core.Deprecated('Use noMoreCandidatesDescriptor instead')
|
||||
const NoMoreCandidates$json = {
|
||||
'1': 'NoMoreCandidates',
|
||||
};
|
||||
|
||||
/// Descriptor for `NoMoreCandidates`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List noMoreCandidatesDescriptor = $convert.base64Decode(
|
||||
'ChBOb01vcmVDYW5kaWRhdGVz');
|
||||
|
||||
@$core.Deprecated('Use iceCandidateDescriptor instead')
|
||||
const IceCandidate$json = {
|
||||
'1': 'IceCandidate',
|
||||
'2': [
|
||||
{'1': 'candidate', '3': 1, '4': 1, '5': 9, '10': 'candidate'},
|
||||
{'1': 'sdp_mid', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'sdpMid', '17': true},
|
||||
{'1': 'sdp_line_index', '3': 3, '4': 1, '5': 5, '9': 1, '10': 'sdpLineIndex', '17': true},
|
||||
{'1': 'username_fragment', '3': 4, '4': 1, '5': 9, '9': 2, '10': 'usernameFragment', '17': true},
|
||||
],
|
||||
'8': [
|
||||
{'1': '_sdp_mid'},
|
||||
{'1': '_sdp_line_index'},
|
||||
{'1': '_username_fragment'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `IceCandidate`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List iceCandidateDescriptor = $convert.base64Decode(
|
||||
'CgxJY2VDYW5kaWRhdGUSHAoJY2FuZGlkYXRlGAEgASgJUgljYW5kaWRhdGUSHAoHc2RwX21pZB'
|
||||
'gCIAEoCUgAUgZzZHBNaWSIAQESKQoOc2RwX2xpbmVfaW5kZXgYAyABKAVIAVIMc2RwTGluZUlu'
|
||||
'ZGV4iAEBEjAKEXVzZXJuYW1lX2ZyYWdtZW50GAQgASgJSAJSEHVzZXJuYW1lRnJhZ21lbnSIAQ'
|
||||
'FCCgoIX3NkcF9taWRCEQoPX3NkcF9saW5lX2luZGV4QhQKEl91c2VybmFtZV9mcmFnbWVudA==');
|
||||
|
||||
@$core.Deprecated('Use iceSessionDescriptionDescriptor instead')
|
||||
const IceSessionDescription$json = {
|
||||
'1': 'IceSessionDescription',
|
||||
'2': [
|
||||
{'1': 'sdp_type', '3': 1, '4': 1, '5': 3, '10': 'sdpType'},
|
||||
{'1': 'sdp', '3': 2, '4': 1, '5': 9, '10': 'sdp'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `IceSessionDescription`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List iceSessionDescriptionDescriptor = $convert.base64Decode(
|
||||
'ChVJY2VTZXNzaW9uRGVzY3JpcHRpb24SGQoIc2RwX3R5cGUYASABKANSB3NkcFR5cGUSEAoDc2'
|
||||
'RwGAIgASgJUgNzZHA=');
|
||||
|
||||
@$core.Deprecated('Use sessionDescriptor instead')
|
||||
const Session$json = {
|
||||
'1': 'Session',
|
||||
'2': [
|
||||
{'1': 'id', '3': 1, '4': 1, '5': 11, '6': '.signaler.Session.Identifier', '10': 'id'},
|
||||
{'1': 'camera', '3': 2, '4': 1, '5': 11, '6': '.signaler.Camera.Identifier', '10': 'camera'},
|
||||
],
|
||||
'3': [Session_Identifier$json],
|
||||
};
|
||||
|
||||
@$core.Deprecated('Use sessionDescriptor instead')
|
||||
const Session_Identifier$json = {
|
||||
'1': 'Identifier',
|
||||
'2': [
|
||||
{'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `Session`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List sessionDescriptor = $convert.base64Decode(
|
||||
'CgdTZXNzaW9uEiwKAmlkGAEgASgLMhwuc2lnbmFsZXIuU2Vzc2lvbi5JZGVudGlmaWVyUgJpZB'
|
||||
'IzCgZjYW1lcmEYAiABKAsyGy5zaWduYWxlci5DYW1lcmEuSWRlbnRpZmllclIGY2FtZXJhGhwK'
|
||||
'CklkZW50aWZpZXISDgoCaWQYASABKAlSAmlk');
|
||||
|
||||
@$core.Deprecated('Use authTokenDescriptor instead')
|
||||
const AuthToken$json = {
|
||||
'1': 'AuthToken',
|
||||
'2': [
|
||||
{'1': 'token', '3': 1, '4': 1, '5': 9, '10': 'token'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `AuthToken`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List authTokenDescriptor = $convert.base64Decode(
|
||||
'CglBdXRoVG9rZW4SFAoFdG9rZW4YASABKAlSBXRva2Vu');
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// Generated code. Do not modify.
|
||||
// source: token/token.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
|
||||
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
import 'dart:core' as $core;
|
||||
|
||||
import 'package:protobuf/protobuf.dart' as $pb;
|
||||
|
||||
class AuthToken extends $pb.GeneratedMessage {
|
||||
factory AuthToken({
|
||||
$core.String? uid,
|
||||
$core.String? home,
|
||||
}) {
|
||||
final $result = create();
|
||||
if (uid != null) {
|
||||
$result.uid = uid;
|
||||
}
|
||||
if (home != null) {
|
||||
$result.home = home;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
AuthToken._() : super();
|
||||
factory AuthToken.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory AuthToken.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'AuthToken', package: const $pb.PackageName(_omitMessageNames ? '' : 'token'), createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'uid')
|
||||
..aOS(2, _omitFieldNames ? '' : 'home')
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
AuthToken clone() => AuthToken()..mergeFromMessage(this);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
AuthToken copyWith(void Function(AuthToken) updates) => super.copyWith((message) => updates(message as AuthToken)) as AuthToken;
|
||||
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static AuthToken create() => AuthToken._();
|
||||
AuthToken createEmptyInstance() => create();
|
||||
static $pb.PbList<AuthToken> createRepeated() => $pb.PbList<AuthToken>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static AuthToken getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<AuthToken>(create);
|
||||
static AuthToken? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get uid => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set uid($core.String v) { $_setString(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasUid() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearUid() => clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get home => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set home($core.String v) { $_setString(1, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasHome() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearHome() => clearField(2);
|
||||
}
|
||||
|
||||
|
||||
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
|
||||
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// Generated code. Do not modify.
|
||||
// source: token/token.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
|
||||
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Generated code. Do not modify.
|
||||
// source: token/token.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
|
||||
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
|
||||
import 'dart:convert' as $convert;
|
||||
import 'dart:core' as $core;
|
||||
import 'dart:typed_data' as $typed_data;
|
||||
|
||||
@$core.Deprecated('Use authTokenDescriptor instead')
|
||||
const AuthToken$json = {
|
||||
'1': 'AuthToken',
|
||||
'2': [
|
||||
{'1': 'uid', '3': 1, '4': 1, '5': 9, '10': 'uid'},
|
||||
{'1': 'home', '3': 2, '4': 1, '5': 9, '10': 'home'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `AuthToken`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List authTokenDescriptor = $convert.base64Decode(
|
||||
'CglBdXRoVG9rZW4SEAoDdWlkGAEgASgJUgN1aWQSEgoEaG9tZRgCIAEoCVIEaG9tZQ==');
|
||||
|
||||
+68
-23
@@ -1,12 +1,30 @@
|
||||
import 'package:flutter/material.dart';
|
||||
//import 'package:grpc/grpc_web.dart';
|
||||
import 'package:grpc/grpc.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:ui/call.dart';
|
||||
import 'package:ui/gen/signaler_service.pbgrpc.dart';
|
||||
import 'package:ui/session_service.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const MyApp());
|
||||
void main() async {
|
||||
Logger logger = Logger();
|
||||
logger.i("Establishing connection...");
|
||||
final channel = ClientChannel(
|
||||
'192.168.0.65',
|
||||
port: 8080,
|
||||
options: const ChannelOptions(credentials: ChannelCredentials.insecure()),
|
||||
channelShutdownHandler: () {
|
||||
logger.e("Channel shutdown unexpectedly");
|
||||
},
|
||||
);
|
||||
final stub = SignalerServiceClient(channel);
|
||||
runApp(MyApp(stub, SessionService(stub)));
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
final SignalerServiceClient client;
|
||||
final SessionService sessionService;
|
||||
const MyApp(this.client, this.sessionService, {super.key});
|
||||
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
@@ -32,13 +50,22 @@ class MyApp extends StatelessWidget {
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: const MyHomePage(title: 'Flutter Demo Home Page'),
|
||||
home: MyHomePage(
|
||||
client,
|
||||
sessionService,
|
||||
title: 'Home Sensors',
|
||||
home: "home1234",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
const MyHomePage({super.key, required this.title});
|
||||
final SignalerServiceClient client;
|
||||
final SessionService sessionService;
|
||||
final String home;
|
||||
const MyHomePage(this.client, this.sessionService,
|
||||
{super.key, required this.title, required this.home});
|
||||
|
||||
// This widget is the home page of your application. It is stateful, meaning
|
||||
// that it has a State object (defined below) that contains fields that affect
|
||||
@@ -56,17 +83,38 @@ class MyHomePage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
int _counter = 0;
|
||||
String topMessage = "Creating session...";
|
||||
List<Call> camerasToRender = [];
|
||||
|
||||
void _incrementCounter() {
|
||||
setState(() {
|
||||
// This call to setState tells the Flutter framework that something has
|
||||
// changed in this State, which causes it to rerun the build method below
|
||||
// so that the display can reflect the updated values. If we changed
|
||||
// _counter without calling setState(), then the build method would not be
|
||||
// called again, and so nothing would appear to happen.
|
||||
_counter++;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_getSession();
|
||||
_listCameras();
|
||||
}
|
||||
|
||||
_getSession() async {
|
||||
var token = await widget.sessionService.getAuthToken(widget.home);
|
||||
topMessage = "Created session $token";
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
_listCameras() async {
|
||||
var callOptions = CallOptions(metadata: {
|
||||
'Authorization': await widget.sessionService.getAuthToken(widget.home)
|
||||
});
|
||||
var cameras = await widget.client
|
||||
.listCameras(ListCamerasRequest(), options: callOptions);
|
||||
|
||||
for (var camera in cameras.cameras) {
|
||||
camerasToRender.add(Call(
|
||||
widget.client,
|
||||
widget.sessionService,
|
||||
cameraID: camera.identifier,
|
||||
home: widget.home,
|
||||
));
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -87,18 +135,15 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
// the App.build method, and use it to set our appbar title.
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: const Center(
|
||||
body: Column(
|
||||
// Center is a layout widget. It takes a single child and positions it
|
||||
// in the middle of the parent.
|
||||
child: Call(
|
||||
host: '',
|
||||
),
|
||||
|
||||
children: <Widget>[
|
||||
Text(topMessage),
|
||||
] +
|
||||
camerasToRender,
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _incrementCounter,
|
||||
tooltip: 'Increment',
|
||||
child: const Icon(Icons.add),
|
||||
), // This trailing comma makes auto-formatting nicer for build methods.
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'package:grpc/grpc_or_grpcweb.dart';
|
||||
import 'package:ui/gen/signaler_service.pbgrpc.dart';
|
||||
|
||||
class SessionService {
|
||||
final SignalerServiceClient _stub;
|
||||
final Map<String, ResponseFuture<AuthToken>> _authTokens = {};
|
||||
|
||||
SessionService(this._stub);
|
||||
|
||||
Future<String> getAuthToken(String cameraID) async {
|
||||
var val = await _authTokens.putIfAbsent(cameraID,
|
||||
() => _stub.createAuthToken(CreateAuthTokenRequest(home: cameraID)));
|
||||
return "Bearer ${val.token}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user