8000 iOS platform video view implementation (a bit buggy) · Condelab/flutter-webrtc@5084cc1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5084cc1

Browse files
committed
iOS platform video view implementation (a bit buggy)
1 parent 8aca1af commit 5084cc1

File tree

11 files changed

+205
-17
lines changed

11 files changed

+205
-17
lines changed

example/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10-
0B2E52A1193C475CC824D4E23320D30B /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 127FE0431EC071958D67B4152ABE0141 /* flutter_assets */; };
1110
229CB39F2D80040AEE1ED23F285ACA94 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A79A511C028ADC462437FA86E6F91AFF /* LaunchScreen.storyboard */; };
1211
5AFE2FDDDEBDE94ED82B40DC8B153987 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 9428FFA3DA242B0B23CE49085F8A8C98 /* GeneratedPluginRegistrant.m */; };
1312
6354C7FECC33A60C0696301773D78092 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 49096491DEF677A67E9C9D1D2F642FB2 /* AppFrameworkInfo.plist */; };
@@ -40,7 +39,6 @@
4039
/* End PBXCopyFilesBuildPhase section */
4140

4241
/* Begin PBXFileReference section */
43-
127FE0431EC071958D67B4152ABE0141 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
4442
21CE142FB216A639B6BE578625A89011 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
4543
2271EF72D6523FE6EB695CB1AFED02B6 /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
4644
2959FB0650C06639B955C55500B01293 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
@@ -119,7 +117,6 @@
119117
D200E37E3AAFC3BCF315E1D381844A67 /* Flutter */ = {
120118
isa = PBXGroup;
121119
children = (
122-
127FE0431EC071958D67B4152ABE0141 /* flutter_assets */,
123120
F6B369AAD73AF22F43C5033650E3A5E7 /* App.framework */,
124121
49096491DEF677A67E9C9D1D2F642FB2 /* AppFrameworkInfo.plist */,
125122
5F00C8B4B6548724073C4AAF93AD0795 /* Debug.xcconfig */,
@@ -182,7 +179,7 @@
182179
TargetAttributes = {
183180
E30F7D64842177B99FDDF63DCA10BCDE = {
184181
CreatedOnToolsVersion = 7.3.1;
185-
DevelopmentTeam = 5J859T6AE8;
182+
DevelopmentTeam = 9P444U4Y39;
186183
SystemCapabilities = {
187184
com.apple.BackgroundModes = {
188185
enabled = 1;
@@ -220,7 +217,6 @@
220217
C43A44975A03EE6E1AB6C84DE6994F08 /* Generated.xcconfig in Resources */,
221218
229CB39F2D80040AEE1ED23F285ACA94 /* LaunchScreen.storyboard in Resources */,
222219
970259CB2284F35CC747F170CC0DF853 /* Main.storyboard in Resources */,
223-
0B2E52A1193C475CC824D4E23320D30B /* flutter_assets in Resources */,
224220
);
225221
runOnlyForDeploymentPostprocessing = 0;
226222
};
@@ -248,8 +244,8 @@
248244
);
249245
inputPaths = (
250246
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
251-
"${PODS_ROOT}/.symlinks/flutter/ios-release/Flutter.framework",
252-
"${PODS_ROOT}/.symlinks/plugins/flutter_webrtc/ios/WebRTC.framework",
247+
"${PODS_ROOT}/.symlinks/flutter/ios/Flutter.framework",
248+
"${PODS_ROOT}/GoogleWebRTC/Frameworks/frameworks/WebRTC.framework",
253249
);
254250
name = "[CP] Embed Pods Frameworks";
255251
outputPaths = (
@@ -384,7 +380,7 @@
384380
ALWAYS_SEARCH_USER_PATHS = NO;
385381
ARCHS = arm64;
386382
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
387-
DEVELOPMENT_TEAM = 5J859T6AE8;
383+
DEVELOPMENT_TEAM = 9P444U4Y39;
388384
ENABLE_BITCODE = NO;
389385
FRAMEWORK_SEARCH_PATHS = (
390386
"$(inherited)",
@@ -464,7 +460,7 @@
464460
ALWAYS_SEARCH_USER_PATHS = NO;
465461
ARCHS = arm64;
466462
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
467-
DEVELOPMENT_TEAM = 5J859T6AE8;
463+
DEVELOPMENT_TEAM = 9P444U4Y39;
468464
ENABLE_BITCODE = NO;
469465
FRAMEWORK_SEARCH_PATHS = (
470466
"$(inherited)",

example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
buildForAnalyzing = "YES">
1515
<BuildableReference
1616
BuildableIdentifier = "primary"
17-
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
17+
BlueprintIdentifier = "E30F7D64842177B99FDDF63DCA10BCDE"
1818
BuildableName = "Runner.app"
1919
BlueprintName = "Runner"
2020
ReferencedContainer = "container:Runner.xcodeproj">
@@ -57,7 +57,7 @@
5757
runnableDebuggingMode = "0">
5858
<BuildableReference
5959
BuildableIdentifier = "primary"
60-
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
60+
BlueprintIdentifier = "E30F7D64842177B99FDDF63DCA10BCDE"
6161
BuildableName = "Runner.app"
6262
BlueprintName = "Runner"
6363
ReferencedContainer = "container:Runner.xcodeproj">

example/ios/Runner/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,7 @@
5656
</array>
5757
<key>UIViewControllerBasedStatusBarAppearance</key>
5858
<false/>
59+
<key>io.flutter.embedded_views_preview</key>
60+
<true/>
5961
</dict>
6062
</plist>

example/lib/src/get_user_media_sample.dart

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ class _GetUserMediaSampleState extends State<GetUserMediaSample> {
5858

5959
try {
6060
var stream = await navigator.getUserMedia(mediaConstraints);
61-
_localStream = stream;
62-
_localRenderer.srcObject = _localStream;
61+
setState(() {
62+
_localStream = stream;
63+
_localRenderer.srcObject = _localStream;
64+
});
6365
} catch (e) {
6466
print(e.toString());
6567
}
@@ -123,10 +125,15 @@ class _GetUserMediaSampleState extends State<GetUserMediaSample> {
123125
builder: (context, orientation) {
124126
return new Center(
125127
child: new Container(
126-
margin: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
127-
width: MediaQuery.of(context).size.width,
128-
height: MediaQuery.of(context).size.height,
129-
child: RTCVideoView(_localRenderer),
128+
// margin: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
129+
// width: MediaQuery.of(context).size.width,
130+
// height: MediaQuery.of(context).size.height,
131+
child: Platform.isIOS
132+
? (_localStream == null
133+
? Container()
134+
: RTCPlatformVideoView(_localStream)
135+
)
136+
: RTCVideoView(_localRenderer),
130137
decoration: new BoxDecoration(color: Colors.black54),
131138
),
132139
);

ios/Classes/FlutterRTCVideoView.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#import <Foundation/Foundation.h>
2+
#import <Flutter/Flutter.h>
3+
#import "WebRTC/RTCMTLVideoView.h"
4+
#import "WebRTC/RTCEAGLVideoView.h"
5+
#import "Flutter/FlutterChannels.h"
6+
< 10000 code>7+
@class FlutterEventChannel;
8+
9+
@interface FlutterRTCVideoView : NSObject<FlutterPlatformView, RTCVideoViewDelegate, FlutterStreamHandler>
10+
11+
@property (strong, nonatomic) RTCEAGLVideoView *videoView;
12+
@property (strong, nonatomic) NSMutableSet<FlutterEventSink> *eventSinks;
13+
@property (nonatomic) CGSize size;
14+
15+
- (instancetype)initWithView:(RTCEAGLVideoView *)view
16+
eventChannel:(FlutterEventChannel *)channel;
17+
18+
@end

ios/Classes/FlutterRTCVideoView.m

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#import <Flutter/Flutter.h>
2+
#import "FlutterRTCVideoView.h"
3+
4+
5+
@implementation FlutterRTCVideoView {
6+
7+
}
8+
- (instancetype)initWithView:(RTCEAGLVideoView *)view eventChannel:(FlutterEventChannel *)channel {
9+
self.videoView = view;
10+
self.eventSinks = [[NSMutableSet alloc] init];
11+
[channel setStreamHandler:self];
12+
view.delegate = self;
13+
return self;
14+
}
15+
16+
- (UIView *)view {
17+
return self.videoView;
18+
}
19+
20+
- (void)videoView:(id <RTCVideoRenderer>)videoView didChangeVideoSize:(CGSize)size {
21+
self.size = size;
22+
[self.videoView setSize:size];
23+
// self.videoView.frame = CGRectMake(0, 0, size.width, size.height);
24+
NSDictionary *event = @{
25+
@"width": @(size.width),
26+
@"height": @(size.height)
27+
};
28+
for (FlutterEventSink sink in self.eventSinks) {
29+
if (sink)
30+
sink(event);
31+
}
32+
}
33+
34+
- (FlutterError *_Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(FlutterEventSink)events {
35+
[self.eventSinks addObject:events];
36+
if (self.size.width != 0 && self.size.height != 0) {
37+
NSDictionary *event = @{
38+
@"width": @(self.size.width),
39+
@"height": @(self.size.height)
40+
};
41+
events(event);
42+
}
43+
return nil;
44+
}
45+
46+
- (FlutterError *_Nullable)onCancelWithArguments:(id _Nullable)arguments {
47+
return nil;
48+
}
49+
50+
51+
@end
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#import <Foundation/Foundation.h>
2+
#import <Flutter/FlutterPlatformViews.h>
3+
#import "FlutterWebRTCPlugin.h"
4+
5+
@interface FlutterWebRTCPlugin (FlutterPlatformViewFactory)
6+
7+
- (NSObject <FlutterPlatformView> *)createWithFrame:(CGRect)frame
8+
viewIdentifier:(int64_t)viewId
9+
arguments:(id _Nullable)args;
10+
11+
- (NSObject <FlutterMessageCodec> *)createArgsCodec;
12+
13+
@end
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#import "FlutterRTCVideoViewFactory.h"
2+
#import "WebRTC/RTCEAGLVideoView.h"
3+
#import <Flutter/FlutterPlatformViews.h>
4+
#import <Flutter/Flutter.h>
5+
#import <WebRTC/RTCMediaStream.h>
6+
#import <WebRTC/RTCVideoTrack.h>
7+
#import <WebRTC/RTCMTLVideoView.h>
8+
#import "FlutterRTCVideoView.h"
9+
10+
11+
@implementation FlutterWebRTCPlugin (FlutterPlatformViewFactory)
12+
13+
- (NSObject <FlutterPlatformView> *)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args {
14+
NSString *streamId = args;
15+
RTCMediaStream *stream = [self streamForId:streamId];
16+
RTCEAGLVideoView *vv = [[RTCEAGLVideoView alloc] initWithFrame:CGRectZero];
17+
FlutterEventChannel *eventChannel = [FlutterEventChannel
18+
eventChannelWithName:[NSString stringWithFormat:@"cloudwebrtc.com/WebRTC/PlatformView%lld", viewId]
19+
binaryMessenger:self.messenger];
20+
RTCVideoTrack *videoTrack = stream.videoTracks[0];
21+
[videoTrack addRenderer:vv];
22+
return [[FlutterRTCVideoView alloc] initWithView:vv eventChannel: eventChannel];
23+
}
24+
25+
- (NSObject <FlutterMessageCodec> *)createArgsCodec {
26+
return FlutterStandardMessageCodec.sharedInstance;
27+
}
28+
29+
@end

ios/Classes/FlutterWebRTCPlugin.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#import "FlutterRTCMediaStream.h"
44
#import "FlutterRTCDataChannel.h"
55
#import "FlutterRTCVideoRenderer.h"
6+
#import "FlutterRTCVideoViewFactory.h"
67

78
#import <AVFoundation/AVFoundation.h>
89
#import <WebRTC/WebRTC.h>
@@ -30,6 +31,7 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
3031
viewController:viewController
3132
withTextures:[registrar textures]];
3233
[registrar addMethodCallDelegate:instance channel:channel];
34+
[registrar registerViewFactory:instance withId:@"FlutterRTCVideoView"];
3335
}
3436

3537
- (instancetype)initWithChannel:(FlutterMethodChannel *)channel

lib/rtc_platform_video_view.dart

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import 'dart:async';
2+
import 'dart:io';
3+
import 'package:flutter/material.dart';
4+
import 'package:flutter/services.dart';
5+
import 'media_stream.dart';
6+
7+
class RTCPlatformVideoView extends StatefulWidget {
8+
final MediaStream _stream;
9+
10+
const RTCPlatformVideoView(this._stream, {Key key}) : super(key: key);
11+
12+
@override
13+
State<StatefulWidget> createState() {
14+
return RTCPlatformVideoState(_stream);
15+
}
16+
}
17+
18+
class RTCPlatformVideoState extends State<RTCPlatformVideoView> {
19+
final MediaStream _stream;
20+
int _platformId;
21+
double _width = 0, _height = 0;
22+
StreamSubscription<dynamic> _eventSubscription;
23+
24+
RTCPlatformVideoState(this._stream);
25+
26+
double get aspectRatio =>
27+
_width == 0 || _height == 0 ? 1 : _width / _height;
28+
29+
double get width => _width;
30+
31+
double get height => _height;
32+
33+
@override
34+
Widget build(BuildContext context) {
35+
assert(Platform.isIOS);
36+
assert(_stream != null);
37+
return AspectRatio(
38+
aspectRatio: aspectRatio,
39+
child: UiKitView(
40+
viewType: "FlutterRTCVideoView",
41+
creationParams: _stream.id,
42+
creationParamsCodec: StandardMessageCodec(),
43+
onPlatformViewCreated: _onCreated,
44+
)
45+
);
46+
}
47+
48+
void _onCreated(int id) {
49+
if (_eventSubscription != null)
50+
return;
51+
_platformId = id;
52+
_eventSubscription = EventChannel('cloudwebrtc.com/WebRTC/PlatformView$id')
53+
.receiveBroadcastStream()
54+
.listen((event) {
55+
print(event);
56+
setState(() {
57+
_width = event['width'];
58+
_height = event['height'];
59+
});
60+
});
61+
}
62+
63+
@override
64+
void dispose() {
65+
_eventSubscription?.cancel();
66+
super.dispose();
67+
}
68+
69+
}

0 commit comments

Comments
 (0)
0