8000 Merge branch 'cloudwebrtc-master' · hicodeboy/flutter-webrtc@6ec6f7f · GitHub
[go: up one dir, main page]

Skip to content

Commit 6ec6f7f

Browse files
committed
Merge branch 'cloudwebrtc-master'
2 parents 7c9250a + 2e436e3 commit 6ec6f7f

File tree

218 files changed

+2114
-3037
lines changed

Original file line numberDiff line numberDiff line change
@@ -1,5 +1,50 @@
11
## Changelog
2+
23
--------------------------------------------
4+
[0.2.7] - 2020.03.15
5+
6+
* [macOS] Fix crash with H264 HW Encoder.
7+
* [Web] Add addTransceiver API.
8+
* [Android] Removed duplicate method that was causing compilation error.
9+
* [iOS] Use MrAlek Libyuv pod fixing incompatibility with FirebaseFirestore.
10+
* [iOS] Upgrade GoogleWebRTC dependency to 1.1.29400.
11+
12+
13+
[0.2.6] - 2020.02.03
14+
15+
* Fixed the interruption of the Bluetooth headset that was playing music after the plugin started.
16+
17+
[0.2.4] - 2020.02.03
18+
19+
* Fixed bug.
20+
21+
[0.2.3] - 2020.02.03
22+
23+
* Fixed bug for enableSpeakerphone (Android/iOS).
24+
* Fix RtcVideoView not rebuild when setState called and renderer is changed.
25+
* Fix Android frame orientation.
26+
27+
[0.2.2] - 2019.12.13
28+
29+
* Removed the soft link of WebRTC.framework to fix compile errors of macos version when third-party flutter app depends on plugins
30+
31+
[0.2.1] - 2019.12.12
32+
33+
* Code format.
34+
* Remove unused files.
35+
36+
[0.2.0] - 2019.12.12
37+
38+
* Add support for macOS (channel dev).
39+
* Add support for Flutter Web (channel dev).
40+
* Add hasTorch support for Android (Camera2 API) and iOS.
41+
* Fix(PeerConnections) split dispose and close
42+
* Add microphone mute support for Android/iOS.
43+
* Add enable speakerphone support for Android/iOS.
44+
* Fix 'createIceServer' method Invalid value error (Android).
45+
* Store SignalingState/IceGatheringState/IceConnectionState in RTCPeerConnection.
46+
* Fixed rendering issues caused by remote MediaStream using the same msid/label when using multiple PeerConntions.
47+
348
[0.1.7] 741A - 2019.05.16
449

550
* Add RTCDataChannelMessage for data channel and remove base64 type.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Contributing
2+
3+
We love contributions from everyone, whether it's raising an issue, reporting a bug, adding a feature, or helping improve a document.
4+
Maintaining the flutter-webrtc plugin for all platforms is not an easy task, so everything you do is support for the project.
5+
6+
# Pull Request
7+
We recommend that you create a related issue before PR so that others can find the answers they want in the issues.
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Flutter-WebRTC
2-
[![pub package](https://img.shields.io/pub/v/flutter_webrtc.svg)](https://pub.dartlang.org/packages/flutter_webrtc) [![Join the chat at https://gitter.im/flutter-webrtc/Lobby](https://badges.gitter.im/flutter-webrtc/Lobby.svg)](https://gitter.im/flutter-webrtc/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
2+
[![Financial Contributors on Open Collective](https://opencollective.com/flutter-webrtc/all/badge.svg?label=financial+contributors)](https://opencollective.com/flutter-webrtc) [![pub package](https://img.shields.io/pub/v/flutter_webrtc.svg)](https://pub.dartlang.org/packages/flutter_webrtc) [![Gitter](https://badges.gitter.im/flutter-webrtc/Lobby.svg)](https://gitter.im/flutter-webrtc/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
33

44
WebRTC plugin for Flutter Mobile/Desktop/Web
55

@@ -30,7 +30,7 @@ This entry allows your app to access camera and microphone.
3030

3131
### Android
3232

33-
Ensure the following permission is present in your Android Manifest file, located in `<project root>/android/app/src/main/AndroidManifest.xml:
33+
Ensure the following permission is present in your Android Manifest file, located in `<project root>/android/app/src/main/AndroidManifest.xml`:
3434

3535
```xml
3636
<uses-feature android:name="android.hardware.camera" />
@@ -58,6 +58,37 @@ android {
5858
## Contributing
5959
The project is inseparable from the contributors of the community.
6060
- [CloudWebRTC](https://github.com/cloudwebrtc) - Original Author
61+
- [RainwayApp](https://github.com/rainwayapp) - Sponsor from Paypal
6162

6263
### Example
6364
For more examples, please refer to [flutter-webrtc-demo](https://github.com/cloudwebrtc/flutter-webrtc-demo/).
65+
66+
## Contributors
67+
68+
### Code Contributors
69+
70+
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
71+
<a href="https://github.com/cloudwebrtc/flutter-webrtc/graphs/contributors"><img src="https://opencollective.com/flutter-webrtc/contributors.svg?width=890&button=false" /></a>
72+
73+
### Financial Contributors
74+
75+
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/flutter-webrtc/contribute)]
76+
77+
#### Individuals
78+
79+
<a href="https://opencollective.com/flutter-webrtc"><img src="https://opencollective.com/flutter-webrtc/individuals.svg?width=890"></a>
80+
81+
#### Organizations
82+
83+
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/flutter-webrtc/contribute)]
84+
85+
<a href="https://opencollective.com/flutter-webrtc/organization/0/website"><img src="https://opencollective.com/flutter-webrtc/organization/0/avatar.svg"></a>
86+
<a href="https://opencollective.com/flutter-webrtc/organization/1/website"><img src="https://opencollective.com/flutter-webrtc/organization/1/avatar.svg"></a>
87+
<a href="https://opencollective.com/flutter-webrtc/organization/2/website"><img src="https://opencollective.com/flutter-webrtc/organization/2/avatar.svg"></a>
88+
<a href="https://opencollective.com/flutter-webrtc/organization/3/website"><img src="https://opencollective.com/flutter-webrtc/organization/3/avatar.svg"></a>
89+
<a href="https://opencollective.com/flutter-webrtc/organization/4/website"><img src="https://opencollective.com/flutter-webrtc/organization/4/avatar.svg"></a>
90+
<a href="https://opencollective.com/flutter-webrtc/organization/5/website"><img src="https://opencollective.com/flutter-webrtc/organization/5/avatar.svg"></a>
91+
<a href="https://opencollective.com/flutter-webrtc/organization/6/website"><img src="https://opencollective.com/flutter-webrtc/organization/6/avatar.svg"></a>
92+
<a href="https://opencollective.com/flutter-webrtc/organization/7/website"><img src="https://opencollective.com/flutter-webrtc/organization/7/avatar.svg"></a>
93+
<a href="https://opencollective.com/flutter-webrtc/organization/8/website"><img src="https://opencollective.com/flutter-webrtc/organization/8/avatar.svg"></a>
94+
<a href="https://opencollective.com/flutter-webrtc/organization/9/website"><img src="https://opencollective.com/flutter-webrtc/organization/9/avatar.svg"></a>
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.cloudwebrtc.webrtc.utils.ConstraintsMap;
1616
import com.cloudwebrtc.webrtc.utils.EglUtils;
1717
import com.cloudwebrtc.webrtc.utils.ObjectType;
18+
import com.cloudwebrtc.webrtc.utils.RTCAudioManager;
1819

1920
import java.io.UnsupportedEncodingException;
2021
import java.io.File;
@@ -72,6 +73,8 @@ public class FlutterWebRTCPlugin implements MethodCallHandler {
7273

7374
private AudioDeviceModule audioDeviceModule;
7475

76+
private RTCAudioManager rtcAudioManager;
77+
7578
public Activity getActivity() {
7679
return registrar.activity();
7780
}
@@ -124,6 +127,62 @@ private FlutterWebRTCPlugin(Registrar registrar, MethodChannel channel) {
124127
.setVideoDecoderFactory(new DefaultVideoDecoderFactory(eglContext))
125128
.setAudioDeviceModule(audioDeviceModule)
126129
.createPeerConnectionFactory();
130+
131+
rtcAudioManager = RTCAudioManager.create(registrar.context());
132+
// Store existing audio settings and change audio mode to
133+
// MODE_IN_COMMUNICATION for best possible VoIP performance.
134+
Log.d(TAG, "Starting the audio manager...");
135+
rtcAudioManager.start(new RTCAudioManager.AudioManagerEvents() {
136+
// This method will be called each time the number of available audio
137+
// devices has changed.
138+
@Override
139+
public void onAudioDeviceChanged(
140+
RTCAudioManager.AudioDevice audioDevice, Set<RTCAudioManager.AudioDevice> availableAudioDevices) {
141+
onAudioManagerDevicesChanged(audioDevice, availableAudioDevices);
142+
}
143+
});
144+
/*
145+
if (audioManager != null) {
146+
audioManager.stop();
147+
audioManager = null;
148+
}
149+
*/
150+
}
151+
152+
private void startAudioManager() {
153+
if(rtcAudioManager != null)
154+
return;
155+
156+
rtcAudioManager = RTCAudioManager.create(registrar.context());
157+
// Store existing audio settings and change audio mode to
158+
// MODE_IN_COMMUNICATION for best possible VoIP performance.
159+
Log.d(TAG, "Starting the audio manager...");
160+
rtcAudioManager.start(new RTCAudioManager.AudioManagerEvents() {
161+
// This method will be called each time the number of available audio
162+
// devices has changed.
163+
@Override
164+
public void onAudioDeviceChanged(
165+
RTCAudioManager.AudioDevice audioDevice, Set<RTCAudioManager.AudioDevice> availableAudioDevices) {
166+
onAudioManagerDevicesChanged(audioDevice, availableAudioDevices);
167+
}
168+
});
169+
}
170+
171+
private void stopAudioManager() {
172+
if (rtcAudioManager != null) {
173+
Log.d(TAG, "Stoping the audio manager...");
174+
rtcAudioManager.stop();
175+
rtcAudioManager = null;
176+
}
177+
}
178+
179+
// This method is called when the audio manager reports audio device change,
180+
// e.g. from wired headset to speakerphone.
181+
private void onAudioManagerDevicesChanged(
182+
final RTCAudioManager.AudioDevice device, final Set<RTCAudioManager.AudioDevice> availableDevices) {
183+
Log.d(TAG, "onAudioManagerDevicesChanged: " + availableDevices + ", "
184+
+ "selected: " + device);
185+
// TODO(henrika): add callback handler.
127186
}
128187

129188
@Override
@@ -265,7 +324,7 @@ public void onMethodCall(MethodCall call, Result notSafeResult) {
265324
result.success(null);
266325
} else if(call.method.equals("peerConnectionDispose")){
267326
String peerConnectionId = call.argument("peerConnectionId");
268-
peerConnectionClose(peerConnectionId);
327+
peerConnectionDispose(peerConnectionId);
269328
result.success(null);
270329
}else if (call.method.equals("createVideoRenderer")) {
271330
TextureRegistry.SurfaceTextureEntry entry = textures.createSurfaceTexture();
@@ -325,14 +384,15 @@ public void onMethodCall(MethodCall call, Result notSafeResult) {
325384
mediaStreamTrackSetVolume(trackId, volume);
326385
result.success(null);
327386
} else if (call.method.equals("setMicrophoneMute")) {
328-
String trackId = call.argument("trackId");
329387
boolean mute = call.argument("mute");
330-
mediaStreamTrackSetMicrophoneMute(trackId, mute);
388+
rtcAudioManager.setMicrophoneMute(mute);
331389
result.success(null);
332390
} else if (call.method.equals("enableSpeakerphone")) {
333-
String trackId = call.argument("trackId");
334391
boolean enable = call.argument("enable");
335-
mediaStreamTrackEnableSpeakerphone(trackId, enable);
392+
if(rtcAudioManager == null ){
393+
startAudioManager();
394+
}
395+
rtcAudioManager.setSpeakerphoneOn(enable);
336396
result.success(null);
337397
} else if(call.method.equals("getDisplayMedia")) {
338398
Map<String, Object> constraints = call.argument("constraints");
@@ -693,6 +753,9 @@ public String peerConnectionInit(
693753
parseMediaConstraints(constraints),
694754
observer);
695755
observer.setPeerConnection(peerConnection);
756+
if(mPeerConnectionObservers.size() == 0) {
757+
startAudioManager();
758+
}
696759
mPeerConnectionObservers.put(peerConnectionId, observer);
697760
return peerConnectionId;
698761
}
@@ -933,24 +996,6 @@ public void mediaStreamTrackSetVolume(final String id, final double volume) {
933996
}
934997
}
935998

936-
public void mediaStreamTrackSetMicrophoneMute(final String id, boolean mute) {
937-
try {
938-
audioDeviceModule.setMicrophoneMute(mute);
939-
} catch (Exception e) {
940-
Log.e(TAG, "setMicrophoneMute(): error", e);
941-
}
942-
}
943-
944-
public void mediaStreamTrackEnableSpeakerphone(final String id, boolean enabled) {
945-
AudioManager audioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
946-
947-
try {
948-
audioManager.setSpeakerphoneOn(enabled);
949-
} catch (Exception e) {
950-
Log.e(TAG, "setSpeakerphoneOn(): error", e);
951-
}
952-
}
953-
954999
public void mediaStreamAddTrack(final String streaemId, final String trackId, Result result) {
9551000
MediaStream mediaStream = localStreams.get(streaemId);
9561001
if (mediaStream != null) {
@@ -1273,6 +1318,9 @@ public void peerConnectionDispose(final String id) {
12731318
pco.dispose();
12741319
mPeerConnectionObservers.remove(id);
12751320
}
1321+
if(mPeerConnectionObservers.size() == 0) {
1322+
stopAudioManager();
1323+
}
12761324
}
12771325

12781326
public void mediaStreamRelease(final String id) {
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ void close() {
8282
remoteTracks.clear();
8383
dataChannels.clear();
8484
}
85-
void dispose(){
85+
86+
void dispose() {
8687
this.close();
8788
peerConnection.dispose();
8889
eventChannel.setStreamHandler(null);
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.cloudwebrtc.webrtc.record;
22

3+
import android.graphics.Bitmap;
4+
import android.graphics.BitmapFactory;
35
import android.graphics.ImageFormat;
6+
import android.graphics.Matrix;
47
import android.graphics.Rect;
58
import android.graphics.YuvImage;
69
import android.os.Handler;
@@ -66,9 +69,12 @@ public void onFrame(VideoFrame videoFrame) {
6669
videoTrack.removeSink(this);
6770
});
6871
try {
69-
if (!file.exists())
72+
if (!file.exists()) {
73+
//noinspection ResultOfMethodCallIgnored
74+
file.getParentFile().mkdirs();
7075
//noinspection ResultOfMethodCallIgnored
7176
file.createNewFile();
77+
}
7278
} catch (IOException io) {
7379
callback.error("IOException", io.getLocalizedMessage(), io);
7480
return;
@@ -79,6 +85,23 @@ public void onFrame(VideoFrame videoFrame) {
7985
100,
8086
outputStream
8187
);
88+
switch (videoFrame.getRotation()) {
89+
case 0:
90+
break;
91+
case 90:
92+
case 180:
93+
case 270:
94+
Bitmap original = BitmapFactory.decodeFile(file.toString());
95+
Matrix matrix = new Matrix();
96+
matrix.postRotate(videoFrame.getRotation());
97+
Bitmap rotated = Bitmap.createBitmap(original, 0, 0, original.getWidth(), original.getHeight(), matrix, true);
98+
FileOutputStream rotatedOutputStream = new FileOutputStream(file);
99+
rotated.compress(Bitmap.CompressFormat.JPEG, 100, rotatedOutputStream);
100+
break;
101+
default:
102+
// Rotation is checked to always be 0, 90, 180 or 270 by VideoFrame
103+
throw new RuntimeException("Invalid rotation");
104+
}
82105
callback.success(null);
83106
} catch (IOException io) {
84107
callback.error("IOException", io.getLocalizedMessage(), io);
@@ -89,4 +112,4 @@ public void onFrame(VideoFrame videoFrame) {
89112
}
90113
}
91114

92-
}
115+
}