Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/guide/get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ audioTrack.dispose();

// Dispose of sources
videoSource.dispose();
audioSource.dispose();

// Close peer connection and release resources
peerConnection.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public static void main(String[] args) {
private static class LocalPeer implements PeerConnectionObserver {

private final RTCPeerConnection peerConnection;
private final AudioTrackSource audioSource;
private final AudioTrack audioTrack;
private final VideoTrack videoTrack;
private final RTCRtpSender audioSender;
Expand All @@ -124,7 +125,7 @@ public LocalPeer(PeerConnectionFactory factory) {
audioOptions.autoGainControl = true;
audioOptions.noiseSuppression = true;

AudioTrackSource audioSource = factory.createAudioSource(audioOptions);
audioSource = factory.createAudioSource(audioOptions);
audioTrack = factory.createAudioTrack("audio0", audioSource);

VideoDeviceSource videoSource = new VideoDeviceSource();
Expand Down Expand Up @@ -160,6 +161,11 @@ public void dispose() {
if (peerConnection != null) {
peerConnection.close();
}
// AudioTrackSource is ref-counted and not owned by the audio
// track; the application must dispose it once no longer needed.
if (audioSource != null) {
audioSource.dispose();
}
}

// PeerConnectionObserver implementation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public class PeerConnectionManager implements PeerConnectionSignalingHandler {
private final PeerConnectionFactory factory;
private final RTCPeerConnection peerConnection;
private final List<RTCRtpSender> senders = new ArrayList<>();
private final List<AudioTrackSource> audioSources = new ArrayList<>();

private Consumer<RTCSessionDescription> onLocalDescriptionCreated;
private Consumer<RTCIceCandidate> onIceCandidateGenerated;
Expand Down Expand Up @@ -120,6 +121,10 @@ public void addTrack(MediaStreamTrack track, List<String> streamIds) {
public AudioTrack createAudioTrack(AudioOptions options, String label) {
AudioTrackSource audioSource = factory.createAudioSource(options);

// Keep the source around so it can be disposed in close(); it is
// ref-counted and not owned by the audio track.
audioSources.add(audioSource);

return factory.createAudioTrack(label, audioSource);
}

Expand Down Expand Up @@ -156,6 +161,11 @@ public void close() {
}
senders.clear();

for (AudioTrackSource audioSource : audioSources) {
audioSource.dispose();
}
audioSources.clear();

if (peerConnection != null) {
peerConnection.close();
}
Expand Down
21 changes: 21 additions & 0 deletions webrtc-jni/src/main/cpp/include/JNI_AudioTrackSource.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions webrtc-jni/src/main/cpp/src/JNI_AudioTrackSource.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2019 Alex Andres
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "JNI_AudioTrackSource.h"
#include "JavaUtils.h"

#include "api/media_stream_interface.h"

#include "rtc_base/logging.h"

JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioTrackSource_dispose
(JNIEnv * env, jobject caller)
{
webrtc::AudioSourceInterface * source = GetHandle<webrtc::AudioSourceInterface>(env, caller);
CHECK_HANDLE(source);

webrtc::RefCountReleaseStatus status = source->Release();

if (status != webrtc::RefCountReleaseStatus::kDroppedLastRef) {
RTC_LOG(LS_WARNING) << "Native object was not deleted. A reference is still around somewhere.";
}

SetHandle<std::nullptr_t>(env, caller, nullptr);

source = nullptr;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,11 @@ protected AudioTrackSource() {

}

/**
* Disposes of the native resources held by this audio source.
* This method should be called when the audio source is no longer needed
* to prevent memory leaks.
*/
public native void dispose();

}
16 changes: 16 additions & 0 deletions webrtc/src/test/java/dev/onvoid/webrtc/media/MediaSourceTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import dev.onvoid.webrtc.TestBase;
import dev.onvoid.webrtc.media.audio.AudioOptions;
import dev.onvoid.webrtc.media.audio.AudioTrack;
import dev.onvoid.webrtc.media.audio.AudioTrackSource;

import org.junit.jupiter.api.Test;
Expand All @@ -32,6 +33,21 @@ void audioSourceStateAfterCreation() {
AudioTrackSource audioSource = factory.createAudioSource(audioOptions);

assertEquals(MediaSource.State.LIVE, audioSource.getState());

audioSource.dispose();
}

@Test
void audioSourceDisposeAfterTrackDispose() {
// Regression test: AudioTrackSource used to have no dispose(), so the
// native AudioSourceInterface reference obtained from
// createAudioSource() could never be released by the application.
AudioOptions audioOptions = new AudioOptions();
AudioTrackSource audioSource = factory.createAudioSource(audioOptions);
AudioTrack audioTrack = factory.createAudioTrack("audio0", audioSource);

audioTrack.dispose();
audioSource.dispose();
}

}
Loading