public class RocReceiver
extends java.lang.Object
Receiver gets the network packets from multiple senders, decodes audio streams from them, mixes multiple streams into a single stream, and returns it to the user.
Receiver is automatically attached to a context when opened and detached from it when closed. The user should not close the context until the receiver is closed.
Receiver work consists of two parts: packet reception and stream decoding. The decoding part is performed in the receiver itself, and the reception part is performed in the context network worker threads.
RocReceiver().setMulticastGroup() function.bind(),
allowing senders connecting to them, or itself connects to remote sender endpoints
using connect(). What approach to use is up to the user.read().
Receiver returns the mixed stream from all connected senders.close(). RocReceiver
class implements AutoCloseable so if it is used in a try-with-resources
statement the object is closed automatically at the end of the statement.
Receiver has one or multiple slots, which may be independently bound or connected.
Slots may be used to bind receiver to multiple addresses. Slots are numbered from
zero and are created automatically. In simple cases just use Slot.DEFAULT.
Each slot has its own set of interfaces, one per each type defined in Interface.
The interface defines the type of the communication with the remote peer
and the set of the protocols supported by it.
Supported actions with the interface:
bind() to bind the interface to a local Endpoint.
In this case the receiver accepts connections from senders mixes their streams into the single output stream.connect() to connect the interface to a remote Endpoint.
In this case the receiver initiates connection to the sender and requests it to
start sending media stream to the receiver.Supported interface configurations:
Interface.CONSOLIDATED to a local endpoint (e.g. be an RTSP server).Interface.CONSOLIDATED to a remote endpoint (e.g. be an RTSP client).Interface.AUDIO_SOURCE, Interface.AUDIO_REPAIR (optionally, for FEC),
and Interface.AUDIO_CONTROL (optionally, for control messages) to local endpoints
(e.g. be an RTP/FECFRAME/RTCP sender).
If Interface.CONSOLIDATED is used, it automatically creates all necessary
transport interfaces and the user should not bother about them.
Otherwise, the user should manually configure Interface.AUDIO_SOURCE and
Interface.AUDIO_REPAIR interfaces:
FecEncoding.DISABLE, only Interface.AUDIO_SOURCE
should be configured. It will be used to transmit audio packets.Interface.AUDIO_SOURCE and Interface.AUDIO_REPAIR
interfaces should be configured. The second interface will be used to transmit redundant repair data.
The protocols for the two interfaces should correspond to each other and to the FEC
scheme. For example, if FecEncoding.RS8M is used, the protocols should be
Protocol.RTP_RS8M_SOURCE and Protocol.RS8M_REPAIR.
A session is identified by the sender address. A session may contain multiple packet streams sent to different receiver ports. If the sender employs FEC, the session will contain source and repair packet streams. Otherwise, the session will contain a single source packet stream.
A session is created automatically on the reception of the first packet from a new address and destroyed when there are no packets during a timeout. A session is also destroyed on other events like a large latency underrun or overrun or broken playback, but if the sender continues to send packets, it will be created again shortly.
The output stream continues no matter how much active sessions there are at the moment. In particular, if there are no sessions, the receiver produces a stream with all zeros.
Sessions can be added and removed from the output stream at any time, probably in the middle of a frame.
Receiver compensates these differences by adjusting the rate of every session stream to the rate of the receiver output stream using a per-session resampler. The frequencies factor between the sender and the receiver clocks is calculated dynamically for every session based on the session incoming packet queue size.
Resampling is a quite time-consuming operation. The user can choose between completely disabling resampling (at the cost of occasional underruns or overruns) or several resampler profiles providing different compromises between CPU consumption and quality.
ClockSource.INTERNAL,
the receiver employs a CPU timer to block reads until it's time to
decode the next bunch of samples according to the configured sample rate.
This mode is useful when the user passes samples to a non-realtime destination, e.g. to an audio file.
ClockSource.EXTERNAL,
the samples read from the receiver are decoded immediately and hence the user is
responsible to call read operation according to the sample rate.
This mode is useful when the user passes samples to a realtime destination with its own clock, e.g. to an audio device. Internal clock should not be used in this case because the audio device and the CPU might have slightly different clocks, and the difference will eventually lead to an underrun or an overrun.
Can be used concurrently
RocReceiverConfig config = RocReceiverConfig.builder()
.frameSampleRate(SAMPLE_RATE)
.frameChannels(ChannelSet.STEREO)
.frameEncoding(FrameEncoding.PCM_FLOAT)
.build();
try (
RocContext context = new RocContext();
RocReceiver receiver = new RocReceiver(context, config);
) {
receiver.bind(Slot.DEFAULT, Interface.AUDIO_SOURCE, new Endpoint("rtp+rs8m://0.0.0.0:0"));
receiver.bind(Slot.DEFAULT, Interface.AUDIO_REPAIR, new Endpoint("rs8m://0.0.0.0:0"));
float[] samples = new float[2];
receiver.read(samples);
}
RocContext,
RocReceiverConfig,
AutoCloseable| Constructor and Description |
|---|
RocReceiver(RocContext context,
RocReceiverConfig config)
Open a new receiver.
|
| Modifier and Type | Method and Description |
|---|---|
void |
bind(Slot slot,
Interface iface,
Endpoint endpoint)
Bind the receiver interface to a local endpoint.
|
void |
close()
Close the native object and unregister it from the
NativeObjectCleaner. |
void |
connect(Endpoint endpoint) |
void |
read(float[] samples)
Read samples from the receiver.
|
void |
setMulticastGroup(Slot slot,
Interface iface,
java.lang.String ip)
Set receiver interface multicast group.
|
public RocReceiver(RocContext context, RocReceiverConfig config) throws java.lang.IllegalArgumentException, java.lang.Exception
Allocates and initializes a new receiver, and attaches it to the context.
context - should point to an opened context.config - should point to an initialized config.java.lang.IllegalArgumentException - if the arguments are invalid.java.lang.Exception - if an error occurred when creating the receiver.public void setMulticastGroup(Slot slot, Interface iface, java.lang.String ip) throws java.lang.IllegalArgumentException, java.lang.Exception
Optional.
Multicast group should be set only when binding receiver interface to an endpoint with multicast IP address. If present, it defines an IP address of the OS network interface on which to join the multicast group. If not present, no multicast group is joined.
It's possible to receive multicast traffic from only those OS network interfaces, on which the process has joined the multicast group. When using multicast, the user should either call this function, or join multicast group manually using OS-specific API.
It is allowed to set multicast group to `0.0.0.0` (for IPv4) or to `::` (for IPv6), to be able to receive multicast traffic from all available interfaces. However, this may not be desirable for security reasons.
Each slot's interface can have only one multicast group. The function should be called
before calling bind() for the interface. It should not be called when
calling connect() for the interface.
Automatically initializes slot with given index if it's used first time.
slot - specifies the receiver slotiface - specifies the receiver interfaceip - should be IPv4 or IPv6 addressjava.lang.IllegalArgumentException - if the arguments are invalid.java.lang.Exceptionpublic void bind(Slot slot, Interface iface, Endpoint endpoint) throws java.lang.IllegalArgumentException, java.io.IOException
Checks that the endpoint is valid and supported by the interface, allocates a new ingoing port, and binds it to the local endpoint.
Each slot's interface can be bound or connected only once. May be called multiple times for different slots or interfaces.
Automatically initializes slot with given index if it's used first time.
If endpoint has explicitly set zero port, the receiver is bound to a randomly
chosen ephemeral port. If the function succeeds, the actual port to which the
receiver was bound is written back to endpoint.
slot - specifies the receiver slotiface - specifies the receiver interfaceendpoint - specifies the receiver endpointjava.lang.IllegalArgumentException - if the arguments are invalid.java.io.IOException - if the address can't be bound or if there are not enough resources.public void connect(Endpoint endpoint)
public void read(float[] samples)
throws java.lang.IllegalArgumentException,
java.io.IOException
Reads network packets received on bound ports, routes packets to sessions, repairs lost packets, decodes samples, resamples and mixes them, and finally stores samples into the provided frame.
If ClockSource.INTERNAL is used, the function blocks until it's time to decode the
samples according to the configured sample rate.
Until the receiver is connected to at least one sender, it produces silence. If the receiver is connected to multiple senders, it mixes their streams into one.
samples - should point to an initialized float array which will be
filled with samples.java.lang.IllegalArgumentException - if the arguments are invalid.java.io.IOException - if there are not enough resources.public void close()
throws java.lang.Exception
NativeObjectCleaner.close in interface java.lang.AutoCloseablejava.lang.Exception - if the underlying roc native object cannot be closed.