Skip to content

Commit f249767

Browse files
authored
feat: add RTCDtmfSender implementation for sending DTMF tones #115 (#183)
1 parent cf9c360 commit f249767

19 files changed

+1013
-92
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ The library provides a comprehensive set of Java classes that map to the WebRTC
2222

2323
For more detailed information, check out the documentation:
2424

25-
- **[Quickstart](https://jrtc.dev/#/quickstart)** - Get up and running quickly with webrtc-java
26-
- **[Guides](https://jrtc.dev/#/guide/overview)** - Comprehensive documentation on using the library
27-
- **[Examples](https://jrtc.dev/#/examples)** - Sample code demonstrating various features
28-
- **[Build Notes](https://jrtc.dev/#/build)** - Instructions for building the library from source
25+
- [Quickstart](https://jrtc.dev/#/quickstart) - Get up and running quickly with webrtc-java
26+
- [Guides](https://jrtc.dev/#/guide/overview) - Comprehensive documentation on using the library
27+
- [Examples](https://jrtc.dev/#/examples) - Sample code demonstrating various features
28+
- [Build Notes](https://jrtc.dev/#/build) - Instructions for building the library from source
2929

3030
## License
3131

docs/_sidebar.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- [Bitrate and Framerate Constraints](guide/constraints.md)
1212
- [Desktop Capture](guide/desktop_capture.md)
1313
- [Data Channels](guide/data_channels.md)
14+
- [DTMF Sender](guide/dtmf_sender.md)
1415
- [RTC Stats](guide/rtc_stats.md)
1516
- [Logging](guide/logging.md)
1617

docs/guide/dtmf_sender.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# DTMF Sender
2+
3+
This guide explains how to use the DTMF (Dual-Tone Multi-Frequency) sender functionality with the webrtc-java library. DTMF senders allow you to send DTMF tones over WebRTC audio connections, which is useful for interactive voice response (IVR) systems and telephony applications.
4+
5+
## Overview
6+
7+
WebRTC DTMF senders allow you to:
8+
- Send DTMF tones over an established audio connection
9+
- Configure tone duration and inter-tone gap
10+
- Monitor tone transmission events
11+
- Check if DTMF tones can be inserted
12+
13+
DTMF tones are the audible tones generated when pressing keys on a telephone keypad. The supported DTMF tones are: 0-9, A-D, *, and #. In addition, the special character ',' (comma) can be used to insert a 2-second delay between tones.
14+
15+
## Getting a DTMF Sender
16+
17+
To use DTMF functionality, you need an established `RTCPeerConnection` with an audio track. You can then get the DTMF sender from the RTP sender associated with the audio track:
18+
19+
```java
20+
import dev.onvoid.webrtc.RTCPeerConnection;
21+
import dev.onvoid.webrtc.RTCRtpSender;
22+
import dev.onvoid.webrtc.RTCDtmfSender;
23+
import dev.onvoid.webrtc.media.audio.AudioTrack;
24+
25+
// Assuming you already have a PeerConnectionFactory and RTCConfiguration
26+
RTCPeerConnection peerConnection = factory.createPeerConnection(config, peerConnectionObserver);
27+
28+
// Create and add an audio track
29+
AudioTrackSource audioSource = factory.createAudioSource(new AudioOptions());
30+
AudioTrack audioTrack = factory.createAudioTrack("audioTrack", audioSource);
31+
32+
// Add the track to the peer connection
33+
List<String> streamIds = new ArrayList<>();
34+
streamIds.add("stream1");
35+
RTCRtpSender sender = peerConnection.addTrack(audioTrack, streamIds);
36+
37+
// Get the DTMF sender
38+
RTCDtmfSender dtmfSender = sender.getDtmfSender();
39+
```
40+
41+
## Checking DTMF Capability
42+
43+
Before attempting to send DTMF tones, you should check if the DTMF sender is capable of sending tones:
44+
45+
```java
46+
if (dtmfSender != null && dtmfSender.canInsertDtmf()) {
47+
// DTMF is supported and can be used
48+
System.out.println("DTMF is supported");
49+
} else {
50+
// DTMF is not supported
51+
System.out.println("DTMF is not supported");
52+
}
53+
```
54+
55+
The `canInsertDtmf()` method returns true if and only if:
56+
- The associated RTCRtpSender's track is non-null and is of kind "audio"
57+
- The RTCDtmfSender is able to send packets
58+
- A "telephone-event" codec has been negotiated
59+
60+
## Sending DTMF Tones
61+
62+
To send DTMF tones, use the `insertDtmf` method:
63+
64+
```java
65+
// Send DTMF tones with custom duration (100ms) and inter-tone gap (70ms)
66+
boolean success = dtmfSender.insertDtmf("123", 100, 70);
67+
```
68+
69+
The `insertDtmf` method takes the following parameters:
70+
- `tones`: A string containing the DTMF tones to send
71+
- `duration`: The duration in milliseconds for each tone (default: 100ms)
72+
- `interToneGap`: The gap between tones in milliseconds (default: 50ms)
73+
74+
The method returns `true` if the tones were successfully queued for transmission, or `false` if the operation failed.
75+
76+
### Valid Tones
77+
78+
The following characters are valid in the `tones` parameter:
79+
- Digits: 0-9
80+
- Letters: A-D (or a-d, case-insensitive)
81+
- Symbols: * (asterisk), # (pound/hash)
82+
- Special: , (comma) - inserts a 2-second delay
83+
84+
Unrecognized characters are ignored.
85+
86+
### Duration and Inter-Tone Gap Constraints
87+
88+
The duration and inter-tone gap parameters have the following constraints:
89+
- Duration must be between 70ms and 6000ms (default: 100ms)
90+
- Inter-tone gap must be at least 50ms (default: 50ms)
91+
92+
If these constraints are not met, the `insertDtmf` method will return `false`.
93+
94+
## Monitoring DTMF Events
95+
96+
To receive notifications about DTMF tone events, implement the `RTCDtmfSenderObserver` interface and register it with the DTMF sender:
97+
98+
```java
99+
import dev.onvoid.webrtc.RTCDtmfSenderObserver;
100+
101+
dtmfSender.registerObserver(new RTCDtmfSenderObserver() {
102+
@Override
103+
public void onToneChange(String tone, String toneBuffer) {
104+
if (tone == null || tone.isEmpty()) {
105+
System.out.println("All tones have been played");
106+
} else {
107+
System.out.println("Playing tone: " + tone);
108+
System.out.println("Remaining tones: " + toneBuffer);
109+
}
110+
}
111+
});
112+
```
113+
114+
The `onToneChange` method is called:
115+
- When a new tone starts playing, with the tone character and the remaining tones buffer
116+
- When all tones have finished playing, with an empty string for both parameters
117+
118+
## Getting DTMF Properties
119+
120+
You can query various properties of the DTMF sender:
121+
122+
```java
123+
// Get the tones currently in the queue
124+
String remainingTones = dtmfSender.tones();
125+
126+
// Get the current duration setting
127+
int duration = dtmfSender.duration();
128+
129+
// Get the current inter-tone gap setting
130+
int interToneGap = dtmfSender.interToneGap();
131+
```
132+
133+
## Cleanup
134+
135+
When you're done with the DTMF sender, you should unregister any observers:
136+
137+
```java
138+
// Unregister the observer
139+
dtmfSender.unregisterObserver();
140+
```
141+
142+
Note that you don't need to explicitly dispose of the DTMF sender, as it will be cleaned up when the associated RTP sender is disposed.
143+
144+
## Best Practices
145+
146+
1. **Check Capability**: Always check if DTMF is supported using `canInsertDtmf()` before attempting to send tones.
147+
148+
2. **Error Handling**: Check the return value of `insertDtmf()` to ensure the tones were successfully queued.
149+
150+
3. **Observer Cleanup**: Always unregister observers when you're done to prevent memory leaks.
151+
152+
4. **Tone Duration**: Use appropriate tone durations based on your application needs:
153+
- For standard telephony applications, the default 100ms is usually sufficient
154+
- For IVR systems that might need more processing time, consider longer durations
155+
156+
5. **Tone Buffering**: Be aware that tones are queued and played sequentially. If you need to cancel queued tones, you can call `insertDtmf("")` to clear the queue.
157+
158+
---
159+
160+
## Conclusion
161+
162+
The RTCDtmfSender provides a standard way to send DTMF tones over WebRTC audio connections. This functionality is particularly useful for applications that need to interact with traditional telephony systems, IVR systems, or any service that uses DTMF for signaling.
163+
164+
By following the guidelines in this document, you can effectively integrate DTMF functionality into your WebRTC applications, enabling users to interact with automated systems or trigger actions using their device's keypad.
165+
166+
For more information on other WebRTC features, refer to the additional guides in the documentation.

docs/guide/overview.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This section provides detailed guides for various features of the webrtc-java li
99
- [Audio Processing](guide/audio_processing.md) - Voice processing components
1010
- [Bitrate and Framerate Constraints](guide/constraints.md) - Controlling media quality
1111
- [Desktop Capture](guide/desktop_capture.md) - Capturing and sharing screens and windows
12+
- [DTMF Sender](guide/dtmf_sender.md) - Sending DTMF tones in a call
1213

1314
## Data Communication
1415

webrtc-jni/src/main/cpp/include/JNI_RTCDtmfSender.h

Lines changed: 69 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

webrtc-jni/src/main/cpp/include/JNI_RTCRtpSender.h

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2019 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef JNI_WEBRTC_API_RTC_DTMF_SENDER_H_
18+
#define JNI_WEBRTC_API_RTC_DTMF_SENDER_H_
19+
20+
#include "JavaClass.h"
21+
#include "JavaRef.h"
22+
23+
#include "api/dtmf_sender_interface.h"
24+
25+
#include <jni.h>
26+
27+
namespace jni
28+
{
29+
namespace RTCDtmfSender
30+
{
31+
class JavaRTCDtmfSenderClass : public JavaClass
32+
{
33+
public:
34+
explicit JavaRTCDtmfSenderClass(JNIEnv * env);
35+
36+
jclass cls;
37+
jmethodID ctor;
38+
};
39+
40+
JavaLocalRef<jobject> toJava(JNIEnv * env);
41+
};
42+
}
43+
44+
#endif
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2019 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef JNI_WEBRTC_API_RTC_DTMF_SENDER_OBSERVER_H_
18+
#define JNI_WEBRTC_API_RTC_DTMF_SENDER_OBSERVER_H_
19+
20+
#include "JavaClass.h"
21+
#include "JavaRef.h"
22+
23+
#include "api/dtmf_sender_interface.h"
24+
25+
#include <jni.h>
26+
#include <memory>
27+
28+
namespace jni
29+
{
30+
class RTCDtmfSenderObserver : public webrtc::DtmfSenderObserverInterface
31+
{
32+
public:
33+
explicit RTCDtmfSenderObserver(JNIEnv * env, const JavaGlobalRef<jobject> & observer);
34+
~RTCDtmfSenderObserver() = default;
35+
36+
// DtmfSenderObserverInterface implementation.
37+
void OnToneChange(const std::string & tone, const std::string & tone_buffer) override;
38+
39+
private:
40+
class JavaRTCDtmfSenderObserverClass : public JavaClass
41+
{
42+
public:
43+
explicit JavaRTCDtmfSenderObserverClass(JNIEnv * env);
44+
45+
jmethodID onToneChange;
46+
};
47+
48+
private:
49+
JavaGlobalRef<jobject> observer;
50+
51+
const std::shared_ptr<JavaRTCDtmfSenderObserverClass> javaClass;
52+
};
53+
}
54+
55+
#endif

0 commit comments

Comments
 (0)