You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Since we have [packets](../glossary/glossary.md#packet) put in order by the [Ordering Buffer](../basic_pipeline/06_OrderingBuffer.md), we can assemble them into the original [frames](../glossary/glossary.md#frame).
4
3
The Depayloader is an element responsible for this task. Specifically speaking, it unpacks the payload from the packets -
5
4
and that is why it's called 'depayloader'.
6
-
Let's create a new module in the `lib/elements/Depayloader.ex` file:
5
+
Let's create a new module in the `lib/elements/depayloader.ex` file:
7
6
8
-
**_`lib/elements/Depayloader.ex`_**
7
+
**_`lib/elements/depayloader.ex`_**
9
8
10
9
```elixir
11
10
defmoduleBasic.Elements.Depayloaderdo
@@ -18,138 +17,160 @@ end
18
17
19
18
What input data do we expect? Of course in `Basic.Format.Packet` format!
We will also need a parameter describing how many packets should we request once we receive a demand for a frame:
44
49
45
-
**_`lib/elements/Depayloader.ex`_**
50
+
**_`lib/elements/depayloader.ex`_**
46
51
47
52
```elixir
48
53
defmoduleBasic.Elements.Depayloaderdo
49
54
...
50
-
def_options(
51
-
packets_per_frame: [
52
-
type::integer,
53
-
spec: pos_integer,
54
-
description:
55
-
"Positive integer, describing how many packets form a single frame. Used to demand the proper number of packets while assembling the frame."
56
-
]
57
-
)
55
+
def_options packets_per_frame: [
56
+
spec: pos_integer,
57
+
description:
58
+
"Positive integer, describing how many packets form a single frame. Used to demand the proper number of packets while assembling the frame."
59
+
]
58
60
...
59
61
end
60
62
```
61
63
62
-
In the `handle_init/1` callback we are simply saving the value of that parameter in the state of our element:
64
+
In the `handle_init/2` callback we are simply saving the value of that parameter in the state of our element:
63
65
64
-
**_`lib/elements/Depayloader.ex`_**
66
+
**_`lib/elements/depayloader.ex`_**
65
67
66
68
```elixir
67
-
@impltrue
68
-
defhandle_init(options) do
69
-
{:ok,
70
-
%{
71
-
frame: [],
72
-
packets_per_frame: options.packets_per_frame
73
-
} }
69
+
defmoduleBasic.Elements.Depayloaderdo
70
+
...
71
+
@impltrue
72
+
defhandle_init(_context, options) do
73
+
{[],
74
+
%{
75
+
frame: [],
76
+
packets_per_frame: options.packets_per_frame
77
+
}}
78
+
end
79
+
...
74
80
end
75
81
```
76
82
77
83
Within the state, we will also hold a (potentially not complete) `:frame` - a list of packets, which form a particular frame. We will aggregate the packets in the `:frame` until the moment the frame is complete.
78
84
79
-
As noted in the [chapter dedicated to the caps](04_Caps.md), since we are changing the type of data within the element, we cannot rely on the default implementation of the `handle_caps/4` callback. We need to explicitly send the updated version of caps:
85
+
As noted in the [chapter dedicated to stream formats](04_StreamFormat.md), since we are changing the type of data within the element, we cannot rely on the default implementation of the `handle_stream_format/4` callback. We need to explicitly send the updated version of the format:
80
86
81
-
**_`lib/elements/Depayloader.ex`_**
87
+
**_`lib/elements/depayloader.ex`_**
82
88
83
89
```elixir
84
-
@impltrue
85
-
defhandle_caps(_pad, _caps, _context, state) do
86
-
caps = %Frame{encoding::utf8}
87
-
{ {:ok, caps: {:output, caps} }, state}
90
+
defmoduleBasic.Elements.Depayloaderdo
91
+
...
92
+
@impltrue
93
+
defhandle_stream_format(:input, _stream_format, _context, state) do
As in most elements, the `handle_demand/5` implementation is quite easy - what we do is simply to make a demand on our `:input` pad once we receive a demand on the `:output` pad. However, since we are expected to produce a frame (which is formed from a particular number of packets) on the `:output` pad, we need to request a particular number of packets on the `:input` pad - that is why we have defined the `:packets_per_frame` option and now we will be making usage of it. In case we would have been asked to produce 10 frames, and each frame would have been made out of 5 packets, then we would need to ask for 10\*5 = 50 packets on the `:input`.
100
+
As in most elements, the `handle_demand/5` implementation is quite easy - what we do is simply make a demand on our `:input` pad once we receive a demand on the `:output` pad. However, since we are expected to produce a frame (which is formed from a particular number of packets) on the `:output` pad, we need to request a particular number of packets on the `:input` pad - that is why we have defined the `:packets_per_frame` option and now we will be making use of it. In case we would have been asked to produce 10 frames, and each frame would have been made out of 5 packets, then we would need to ask for 10\*5 = 50 packets on the `:input`.
92
101
93
-
**_`lib/elements/Depayloader.ex`_**
102
+
**_`lib/elements/depayloader.ex`_**
94
103
95
104
```elixir
96
-
@impltrue
97
-
defhandle_demand(_ref, size, _unit, _ctx, state) do
There is nothing left apart from processing the input data - that is - the packets. Since the packets are coming in order, we can simply hold them in the `:frame` list until all the packets forming that frame will be there. As you might remember, each packet has a frame id in its header, which can be followed by a 'b' or 'e' character, indicating the type of the packet (the one begging a frame or the one ending the frame). We will use information about the type to find a moment in which we should produce a frame out of the packets list.
115
+
There is nothing left apart from processing the input data - that is - the packets. Since the packets are coming in order, we can simply hold them in the `:frame` list until all the packets forming that frame will be there. As you might remember, each packet has a frame id in its header, which can be followed by a 'b' or 'e' character, indicating the type of the packet (the one beginning a frame or the one ending the frame). We will use information about the type to find a moment in which we should produce a frame out of the packets list.
103
116
104
-
**_`lib/elements/Depayloader.ex`_**
117
+
**_`lib/elements/depayloader.ex`_**
105
118
106
119
```elixir
107
-
@impltrue
108
-
defhandle_process(_ref, buffer, _ctx, state) do
109
-
packet = buffer.payload
120
+
defmoduleBasic.Elements.Depayloaderdo
121
+
...
122
+
@impltrue
123
+
defhandle_buffer(:input, buffer, _context, state) do
Now, depending on the type of frame, we perform different actions.
146
-
If we have the 'ending' packet, we are making the `:buffer` action with the frame made out of the packets (that's where `prepare_frame/1` function comes in handy), and clear the `:frame` buffer. Here is how can the `prepare_frame/1` function be implemented:
163
+
If we have the 'ending' packet, we are making the `:buffer` action with the frame made out of the packets (that's where `prepare_frame/1` function comes in handy), and clear the `:frame` buffer. Here is how the `prepare_frame/1` function can be implemented:
147
164
148
-
**_`lib/elements/Depayloader.ex`_**
165
+
**_`lib/elements/depayloader.ex`_**
149
166
150
167
```elixir
151
-
defpprepare_frame(frame) do
152
-
frame |>Enum.reverse() |>Enum.join("")
168
+
defmoduleBasic.Elements.Depayloaderdo
169
+
...
170
+
defpprepare_frame(frame) do
171
+
frame |>Enum.reverse() |>Enum.join("")
172
+
end
173
+
...
153
174
end
154
175
```
155
176
@@ -161,5 +182,5 @@ Test the `Depayloader`:
161
182
mix test test/elements/depayloader_test.exs
162
183
```
163
184
164
-
With the [`Source`](../glossary/glossary.md#source), [`OrderingBuffer`](../glossary/glossary.md#jitter-buffer--ordering-buffer) and [`Depayloader`](../glossary/glossary.md#payloader-and-depayloader) elements ready we are able to read packets from file, order them based on their sequence id and assemble them back into frames.
165
-
In the next chapter we will be dealing with [`Mixer`](../glossary/glossary.md#mixer) which will merge two message streams in order to create complete conversation.
185
+
With the [`Source`](../glossary/glossary.md#source), [`OrderingBuffer`](../glossary/glossary.md#jitter-buffer--ordering-buffer) and [`Depayloader`](../glossary/glossary.md#payloader-and-depayloader) elements ready we are able to read packets from file, order them based on their sequence ID and assemble them back into frames.
186
+
In the next chapter we will be dealing with the [`Mixer`](../glossary/glossary.md#mixer) which will merge two message streams in order to create complete conversation.
0 commit comments