Skip to content

Commit

Permalink
chore: cleanup x3rtp script + endpoint
Browse files Browse the repository at this point in the history
Co-authored-by: Sven Uhlig <[email protected]>
  • Loading branch information
Takuto88 and sipgate-uhlig committed Nov 15, 2024
1 parent 39d328d commit 05d13d5
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 20 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@ build/
.vscode/

.DS_Store

### Downloaded audio files
*.mp3
*.raw
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,28 @@ docker compose exec -i simulator \
-key /mutual-tls-stores/keys/network-element.key"
```

## Retrieving X3 RTP Audio

The simulator can be used to actually dump all RTP audio packets and create an MP3. To do this, send your RTP-Stream via X3 to the simulator on port 42069.
It is out of scope how you do this - use your NE for example.

After you have sent the RTP-Stream, you can retrieve the audio by using the following commands:

```shell
python3 -m venv .venv
source .venv/bin/activate
pip3 install -r scripts/requirements.txt
python3 scripts/download-x3rtp-and-convert.py http://localhost:8080 [XID] [in|out]
```

Replace `[XID]` with the XID of the call you want to retrieve and `[in|out]` with the direction of the call. The script will download the RTP packets and convert them to an MP3 file called `[XID]-[DIRECTION].mp3`.

Be sure to reset the X2X3 in-memory receiver after you have downloaded the audio.

```shell
curl -X POST "http://localhost:8080/x2x3/reset"
```

## Further information

- EVE Explains: ETSI TS 103 221 - X1/X2/X3 https://www.lawfulinterception.com/explains/etsi-ts-103-221/
2 changes: 1 addition & 1 deletion docker-compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ services:
MVN_ADDITIONAL_ARGS: "-DskipTests"
ports:
- "127.0.0.1:8080:8080" # REST API
- "127.0.0.1:42069:42069" # X2
- "127.0.0.1:42069:42069" # X2X3
- "127.0.0.1:5005:5005" # JVM remote debug
networks:
- li-network
Expand Down
2 changes: 1 addition & 1 deletion scripts/download-x3rtp-and-convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

def main(sim_url, xid, direction):
# GET from simurl with request path
resp = requests.get(f"{sim_url}/x2x3/all/rtp/{xid}/{direction}")
resp = requests.get(f"{sim_url}/x2x3/{xid}/rtp/{direction}")
# get body of response as byte string
data = resp.content
# get header "X-Payload-Types"
Expand Down
1 change: 1 addition & 0 deletions scripts/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
requests==2.32.3
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,20 @@
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/x2x3")
public class X2X3Controller {

private final X2X3Memory x2X3Memory;
private final Logger LOGGER = LoggerFactory.getLogger(X2X3Controller.class);
private static final Logger LOGGER = LoggerFactory.getLogger(X2X3Controller.class);

public X2X3Controller(final X2X3Memory x2X3Memory) {
this.x2X3Memory = x2X3Memory;
Expand All @@ -45,7 +35,7 @@ public X2X3Controller(final X2X3Memory x2X3Memory) {
@Operation(summary = "Reset X2X3 Storage")
@ApiResponses(value = { @ApiResponse(responseCode = "204", description = "No Content") })
@PostMapping("/reset")
public ResponseEntity<Void> reset() throws IOException {
public ResponseEntity<Void> reset() {
x2X3Memory.reset();
LOGGER.info("Reset completed");

Expand Down Expand Up @@ -85,7 +75,7 @@ public ResponseEntity<String> getLast() throws IOException {
}
)
@GetMapping("/all")
public ResponseEntity<List<String>> getAll() throws IOException {
public ResponseEntity<List<String>> getAll() {
final var respList = getStorageAsList(pdu -> true);
return ResponseEntity.ok(respList);
}
Expand All @@ -100,14 +90,14 @@ public ResponseEntity<List<String>> getAll() throws IOException {
}
)
@GetMapping("/all/x3")
public ResponseEntity<List<String>> getAllX3() throws IOException {
public ResponseEntity<List<String>> getAllX3() {
final var respList = getStorageAsList(pdu -> PduType.X3_PDU.equals(pdu.pduType()));
return ResponseEntity.ok(respList);
}

// ================================

@GetMapping(value = "/all/rtp/{xid}/{direction}")
@GetMapping(value = "/{xid}/rtp/{direction}")
public ResponseEntity<byte[]> getAllRtp(@PathVariable final UUID xid, @PathVariable final String direction)
throws IOException {
final var liMediaExtractor = new RtpMediaExtractor();
Expand All @@ -128,7 +118,7 @@ public ResponseEntity<byte[]> getAllRtp(@PathVariable final UUID xid, @PathVaria
final var payloadTypeNames = String.join(",", liMediaExtractor.getPayloadTypeNames());
LOGGER.info("Extracted types: {}", payloadTypeNames);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM) // TODO: set the content type from getPayloadTypeNames()?
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header("X-Payload-Types", payloadTypeNames)
.body(buf.toByteArray());
}
Expand Down

0 comments on commit 05d13d5

Please sign in to comment.