收到videoCall的远程流时的代码:
/**
* Received remote peer's media stream. we will get the first video track and render it
*/
private void gotRemoteStream(MediaStream stream) {
LogUtil.prependCallLocation("REMOTE STREAM GOTEN");
//we have remote video stream. add to the renderer.
final VideoTrack videoTrack = stream.videoTracks.get(0);
runOnUiThread(() -> {
try {
videoTrack.addSink(remoteVideoView);
} catch (Exception e) {
e.printStackTrace();
LogUtil.prependCallLocation("ERROR HAPPEND HERE");
}
});
}
现在,我正在将JUST音轨发送给同伴,因此我想播放该音轨。 (我只想在没有视频流的情况下实现语音通话)
新代码
private void gotRemoteStream(MediaStream stream) {
LogUtil.prependCallLocation("REMOTE STREAM GOTEN");
//Im getting Audio Track of the stream and i should play it somehow
final AudioTrack audioTrack = stream.audioTracks.get(0);
runOnUiThread(() -> {
try {
} catch (Exception e) {
e.printStackTrace();
LogUtil.prependCallLocation("ERROR HAPPEND HERE");
}
});
}
如何在本地播放audioTrack
?
答案 0 :(得分:0)
已解决。
如果有人遇到相同的问题。 WebRTC自己处理音频流,您不必尝试播放它。
因此,如果您只想创建语音通话, 删除所有与视频渲染相关的请求,并且该请求有效。
在创建要约时要牢记,您必须从MediaConstraints中删除“ OfferToReceiveVideo
”。
(在我的情况下,该崩溃导致没有日志错误)。
完成AudioCall活动类:
public class AudioCallActivity extends AppCompatActivity implements View.OnClickListener, SignallingClient.SignalingInterface {
PeerConnectionFactory peerConnectionFactory;
MediaConstraints audioConstraints;
MediaConstraints sdpConstraints;
AudioSource audioSource;
AudioTrack localAudioTrack;
Button hangup;
PeerConnection localPeer;
List<IceServer> iceServers;
boolean gotUserMedia;
private boolean hangedUp;
BlastVisualizer mVisualizer;
List<PeerConnection.IceServer> peerIceServers = new ArrayList<>();
AudioManager audioManager;
private String roomName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_audio_call);
initViews();
getIceServers();
roomName = Objects.requireNonNull(getIntent().getExtras()).getString("roomName",null);
Toast.makeText(this, "roomName = " + roomName, Toast.LENGTH_SHORT).show();
}
private void initViews() {
hangup = findViewById(R.id.end_call);
hangup.setOnClickListener(this);
}
private void getIceServers() {
hangedUp = false;
//get Ice servers using xirsys
byte[] data;
data = ("yourICEServerAuthKey").getBytes(StandardCharsets.UTF_8);
String authToken = "Basic " + Base64.encodeToString(data, Base64.NO_WRAP);
Utils.getInstance().getRetrofitInstance().getIceCandidates(authToken).enqueue(new Callback<TurnServerPojo>() {
@Override
public void onResponse(@NonNull Call<TurnServerPojo> call, @NonNull Response<TurnServerPojo> response) {
TurnServerPojo body = response.body();
if (body != null) {
iceServers = body.iceServerList.iceServers;
}
// Toast.makeText(VideoCallActivity.this, "Ice Servers Received", Toast.LENGTH_SHORT).show();
for (IceServer iceServer : iceServers) {
if (iceServer.credential == null) {
PeerConnection.IceServer peerIceServer =
PeerConnection
.IceServer
.builder(iceServer.url)
.createIceServer();
peerIceServers
.add(peerIceServer);
} else {
PeerConnection.IceServer peerIceServer =
PeerConnection.IceServer.builder(iceServer.url)
.setUsername(iceServer.username)
.setPassword(iceServer.credential)
.createIceServer();
peerIceServers.add(peerIceServer);
}
}
SignallingClient.getInstance().init(AudioCallActivity.this,roomName);
start();
}
@Override
public void onFailure(@NonNull Call<TurnServerPojo> call, @NonNull Throwable t) {
t.printStackTrace();
LogUtil.prependCallLocation("On Failure" + t);
}
});
}
public void start() {
//Initialize PeerConnectionFactory globals.
PeerConnectionFactory.InitializationOptions initializationOptions =
PeerConnectionFactory.InitializationOptions.builder(this)
.createInitializationOptions();
PeerConnectionFactory.initialize(initializationOptions);
//Create a new PeerConnectionFactory instance - using Hardware encoder and decoder.
PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
peerConnectionFactory = PeerConnectionFactory.builder()
.setOptions(options)
.createPeerConnectionFactory();
//Create MediaConstraints - Will be useful for specifying video and audio constraints.
audioConstraints = new MediaConstraints();
//create an AudioSource instance
audioSource = peerConnectionFactory.createAudioSource(audioConstraints);
localAudioTrack = peerConnectionFactory.createAudioTrack("101", audioSource);
//showToast("GotUserMedia Sets True");
gotUserMedia = true;
if (SignallingClient.getInstance().isInitiator) {
onTryToStart();
}
}
/**
* This method will be called directly by the app when it is the initiator and has got the local media
* or when the remote peer sends a message through socket that it is ready to transmit AV data
*/
@Override
public void onTryToStart() {
runOnUiThread(() -> {
if (!SignallingClient.getInstance().isStarted && SignallingClient.getInstance().isChannelReady) {
createPeerConnection();
SignallingClient.getInstance().isStarted = true;
if (SignallingClient.getInstance().isInitiator) {
doCall();
}
}
});
}
/**
* Creating the local peerconnection instance
*/
private void createPeerConnection() {
PeerConnection.RTCConfiguration rtcConfig =
new PeerConnection.RTCConfiguration(peerIceServers);
// TCP candidates are only useful when connecting to a server that supports
// ICE-TCP.
rtcConfig.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED;
rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE;
rtcConfig.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE;
rtcConfig.continualGatheringPolicy = PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY;
// Use ECDSA encryption.
rtcConfig.keyType = PeerConnection.KeyType.ECDSA;
localPeer = peerConnectionFactory.createPeerConnection(rtcConfig, new CustomPeerConnectionObserver("localPeerCreation") {
@Override
public void onIceCandidate(IceCandidate iceCandidate) {
super.onIceCandidate(iceCandidate);
onIceCandidateReceived(iceCandidate);
}
@Override
public void onAddStream(MediaStream mediaStream) {
//showToast("Received Remote stream");
super.onAddStream(mediaStream);
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.setSpeakerphoneOn(false);
}
});
addStreamToLocalPeer();
}
/**
* Adding the stream to the localpeer
*/
private void addStreamToLocalPeer() {
MediaStream stream = peerConnectionFactory.createLocalMediaStream("101");
stream.addTrack(localAudioTrack);
localPeer.addStream(stream);
}
/**
* This method is called when the app is initiator - We generate the offer and send it over through socket
* to remote peer
*/
private void doCall() {
sdpConstraints = new MediaConstraints();
sdpConstraints.mandatory.add(
new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
localPeer.createOffer(new CustomSdpObserver("localCreateOffer") {
@Override
public void onCreateSuccess(SessionDescription sessionDescription) {
super.onCreateSuccess(sessionDescription);
localPeer.setLocalDescription(new CustomSdpObserver("localSetLocalDesc"), sessionDescription);
LogUtil.prependCallLocation("SignallingClient emit ");
SignallingClient.getInstance().emitMessage(sessionDescription);
}
}, sdpConstraints);
}
/**
* Received local ice candidate. Send it to remote peer through signalling for negotiation
*/
public void onIceCandidateReceived(IceCandidate iceCandidate) {
//we have received ice candidate. We can set it to the other peer.
SignallingClient.getInstance().emitIceCandidate(iceCandidate);
}
/**
* SignallingCallback - called when the room is created - i.e. you are the initiator
*/
@Override
public void onCreatedRoom() {
if (gotUserMedia) {
SignallingClient.getInstance().emitMessage("got user media");
}
}
/**
* SignallingCallback - called when you join the room - you are a participant
*/
@Override
public void onJoinedRoom() {
if (gotUserMedia) {
SignallingClient.getInstance().emitMessage("got user media");
}
}
@Override
public void onNewPeerJoined() {
showToast("Remote Peer Joined");
}
@Override
public void onHangupReqReceived(String msg) {
runOnUiThread(this::hangup);
}
/**
* SignallingCallback - Called when remote peer sends offer
*/
@Override
public void onOfferReceived(final JSONObject data) {
//showToast("Received Offer");
runOnUiThread(() -> {
if (!SignallingClient.getInstance().isInitiator && !SignallingClient.getInstance().isStarted) {
onTryToStart();
}
try {
localPeer.setRemoteDescription(new CustomSdpObserver("localSetRemote"), new SessionDescription(SessionDescription.Type.OFFER, data.getString("sdp")));
doAnswer();
} catch (JSONException e) {
e.printStackTrace();
}
});
}
private void doAnswer() {
localPeer.createAnswer(new CustomSdpObserver("localCreateAns") {
@Override
public void onCreateSuccess(SessionDescription sessionDescription) {
super.onCreateSuccess(sessionDescription);
localPeer.setLocalDescription(new CustomSdpObserver("localSetLocal"), sessionDescription);
SignallingClient.getInstance().emitMessage(sessionDescription);
}
}, new MediaConstraints());
}
/**
* SignallingCallback - Called when remote peer sends answer to your offer
*/
@Override
public void onAnswerReceived(JSONObject data) {
// showToast("Received Answer");
try {
localPeer.setRemoteDescription(new CustomSdpObserver("localSetRemote"), new SessionDescription(SessionDescription.Type.fromCanonicalForm(data.getString("type").toLowerCase()), data.getString("sdp")));
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* Remote IceCandidate received
*/
@Override
public void onIceCandidateReceived(JSONObject data) {
try {
localPeer.addIceCandidate(new IceCandidate(data.getString("id"), data.getInt("label"), data.getString("candidate")));
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* Closing up - normal hangup and app destroye
*/
@Override
public void onClick(View v) {
if (v.getId() == R.id.end_call) {
sendHangUpReq();
}
}
private void sendHangUpReq() {
SignallingClient.getInstance().sendHangupReq();
}
private void hangup() {
if(hangedUp)return;
hangedUp = true;
try {
if(localPeer != null)
localPeer.close();
localPeer= null;
SignallingClient.getInstance().close();
finish();
} catch (Exception e) {
Log.e("Exception Happend","ExceptionHappend");
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
hangup();
finish();
}
public void showToast(final String msg) {
runOnUiThread(() -> Toast.makeText(AudioCallActivity.this, msg, Toast.LENGTH_SHORT).show());
}
}