/* * Copyright (C) 2018 Intel Corporation * SPDX-License-Identifier: Apache-2.0 */ package owt.conference; import static owt.base.CheckCondition.DCHECK; import android.util.Log; import owt.base.AudioCodecParameters; import owt.base.AudioEncodingParameters; import owt.base.LocalStream; import owt.base.PeerConnectionChannel; import owt.base.Stream; import owt.base.VideoCodecParameters; import owt.base.VideoEncodingParameters; import org.webrtc.IceCandidate; import org.webrtc.MediaStream; import org.webrtc.PeerConnection; import org.webrtc.RtpReceiver; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; final class ConferencePeerConnectionChannel extends PeerConnectionChannel { private final List<IceCandidate> queuedLocalCandidates; Stream stream; // CPCC has either a publication or a subscription, cannot have them both. Publication publication; Subscription subscription; private boolean remoteSdpSet = false; ConferencePeerConnectionChannel(String key, PeerConnection.RTCConfiguration configuration, boolean receiveVideo, boolean receiveAudio, PeerConnectionChannelObserver observer) { super(key, configuration, receiveVideo, receiveAudio, observer); queuedLocalCandidates = new LinkedList<>(); } void publish(LocalStream localStream, PublishOptions options) { stream = localStream; if (options != null && options.videoEncodingParameters != null && options.videoEncodingParameters.size() != 0) { videoCodecs = new ArrayList<>(); for (VideoEncodingParameters param : options.videoEncodingParameters) { videoCodecs.add(param.codec.name); } videoMaxBitrate = VideoEncodingParameters.maxBitrate; } if (options != null && options.audioEncodingParameters != null && options.audioEncodingParameters.size() != 0) { audioCodecs = new ArrayList<>(); for (AudioEncodingParameters param : options.audioEncodingParameters) { audioCodecs.add(param.codec.name); } audioMaxBitrate = AudioEncodingParameters.maxBitrate; } addStream(GetMediaStream(localStream)); createOffer(); } void subscribe(RemoteStream remoteStream, SubscribeOptions options) { stream = remoteStream; if (options != null && options.videoOption != null && options.videoOption.codecs.size() != 0) { videoCodecs = new ArrayList<>(); for (VideoCodecParameters param : options.videoOption.codecs) { videoCodecs.add(param.name); } } if (options != null && options.audioOption != null && options.audioOption.codecs.size() != 0) { audioCodecs = new ArrayList<>(); for (AudioCodecParameters param : options.audioOption.codecs) { audioCodecs.add(param.name); } } createOffer(); } protected synchronized void dispose() { super.dispose(); if (publication != null) { DCHECK(subscription == null); publication.onEnded(); } if (subscription != null) { DCHECK(publication == null); subscription.onEnded(); } } @Override public void onSetSuccess() { if (signalingState == PeerConnection.SignalingState.STABLE) { remoteSdpSet = true; for (IceCandidate iceCandidate : queuedLocalCandidates) { observer.onIceCandidate(key, iceCandidate); } queuedLocalCandidates.clear(); if (stream instanceof LocalStream) { setMaxBitrate(stream.id()); } } } @Override public void onCreateFailure(final String error) { callbackExecutor.execute(() -> observer.onError(key, error, false)); } @Override public void onSetFailure(final String error) { callbackExecutor.execute(() -> observer.onError(key, error, false)); } @Override public void onSignalingChange(final PeerConnection.SignalingState signalingState) { callbackExecutor.execute( () -> ConferencePeerConnectionChannel.this.signalingState = signalingState); } @Override public void onIceConnectionChange(final PeerConnection.IceConnectionState iceConnectionState) { callbackExecutor.execute(() -> { if (iceConnectionState == PeerConnection.IceConnectionState.CLOSED) { observer.onEnded(key); } if (iceConnectionState == PeerConnection.IceConnectionState.FAILED) { observer.onError(key, "ICE connection failed.", false); } }); } @Override public void onIceCandidate(final IceCandidate iceCandidate) { callbackExecutor.execute(() -> { if (remoteSdpSet) { observer.onIceCandidate(key, iceCandidate); } else { queuedLocalCandidates.add(iceCandidate); } }); } @Override public void onIceCandidatesRemoved(IceCandidate[] iceCandidates) { observer.onIceCandidatesRemoved(key, iceCandidates); } @Override public void onAddStream(final MediaStream mediaStream) { DCHECK(stream); callbackExecutor.execute(() -> { ((RemoteStream) stream).setMediaStream(mediaStream); observer.onAddStream(key, (owt.base.RemoteStream) stream); }); } @Override public void onRemoveStream(MediaStream mediaStream) { callbackExecutor.execute(() -> ((RemoteStream) stream).onEnded()); } @Override public void onRenegotiationNeeded() { } @Override public void onAddTrack(RtpReceiver rtpReceiver, MediaStream[] mediaStreams) { } }