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
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ jobs:
target: esp32s3
- path: 'components/pid/example'
target: esp32
- path: 'components/rtsp/example'
target: esp32
- path: 'components/serialization/example'
target: esp32
- path: 'components/socket/example'
Expand Down
3 changes: 3 additions & 0 deletions components/rtsp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
idf_component_register(
INCLUDE_DIRS "include"
REQUIRES logger task socket)
21 changes: 21 additions & 0 deletions components/rtsp/example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)

# add the component directories that we want to use
set(EXTRA_COMPONENT_DIRS
"../../../components/"
)

set(
COMPONENTS
"main esptool_py logger task rtsp wifi"
CACHE STRING
"List of components to include"
)

project(rtsp_example)

set(CMAKE_CXX_STANDARD 20)
67 changes: 67 additions & 0 deletions components/rtsp/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
_Note that this is a template for an ESP-IDF example README.md file. When using this template, replace all these emphasised placeholders with example-specific content._

| Supported Targets | _Supported target, e.g. ESP32_ | _Another supported target, e.g. ESP32-S3_ |
| ----------------- | ------------------------------ | ----------------------------------------- |

_If the example supports all targets supported by ESP-IDF then the table can be omitted_
# _Example Title_

(See the README.md file in the upper level 'examples' directory for more information about examples.)

_What is this example? What does it do?_

_What features of ESP-IDF does it use?_

_What could someone create based on this example? ie applications/use cases/etc_

_If there are any acronyms or Espressif-only words used here, explain them or mention where in the datasheet/TRM this information can be found._

## How to use example

### Hardware Required

_If possible, example should be able to run on any commonly available ESP32 development board. Otherwise, describe what specific hardware should be used._

_If any other items (server, BLE device, app, second chip, whatever) are needed, mention them here. Include links if applicable. Explain how to set them up._

### Configure the project

```
idf.py menuconfig
```

* _If there is any project configuration that the user must set for this example, mention this here._

### Build and Flash

Build the project and flash it to the board, then run monitor tool to view serial output:

```
idf.py -p PORT flash monitor
```

(Replace PORT with the name of the serial port to use.)

(To exit the serial monitor, type ``Ctrl-]``.)

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

## Example Output

_Include an example of the console output from the running example, here:_

```
Use this style for pasting the log.
```

_If the user is supposed to interact with the example at this point (read/write GATT attribute, send HTTP request, press button, etc. then mention it here)_

_For examples where ESP32 is connected with some other hardware, include a table or schematics with connection details._

## Troubleshooting

_If there are any likely problems or errors which many users might encounter, mention them here. Remove this section for very simple examples where nothing is likely to go wrong._

## Example Breakdown

_If the example source code is lengthy, complex, or cannot be easily understood, use this section to break down and explain the source code. This can be done by breaking down the execution path step by step, or explaining what each major function/task/source file does. Add sub titles if necessary. Remove this section for very simple examples where the source code is self explanatory._
2 changes: 2 additions & 0 deletions components/rtsp/example/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS ".")
27 changes: 27 additions & 0 deletions components/rtsp/example/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
menu "RTSP Example Configuration"

config RTSP_SERVER_PORT
int "RTSP Server Port"
default 8554
help
The port number of the RTSP server.

config ESP_WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.

config ESP_WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.

config ESP_MAXIMUM_RETRY
int "Maximum retry"
default 5
help
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.

endmenu
3 changes: 3 additions & 0 deletions components/rtsp/example/main/jpeg_image.hpp

Large diffs are not rendered by default.

122 changes: 122 additions & 0 deletions components/rtsp/example/main/rtsp_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#include <algorithm>
#include <chrono>
#include <functional>
#include <iterator>
#include <thread>

#include "sdkconfig.h"

#if CONFIG_ESP32_WIFI_NVS_ENABLED
#include "nvs_flash.h"
#endif

#include "logger.hpp"
#include "task.hpp"
#include "wifi_sta.hpp"

#include "rtsp_server.hpp"
#include "rtsp_client.hpp"

#include "jpeg_image.hpp"

using namespace std::chrono_literals;
using namespace std::placeholders;

extern "C" void app_main(void) {
espp::Logger logger({.tag = "main", .level = espp::Logger::Verbosity::INFO});

logger.info("Starting RTSP example!");

#if CONFIG_ESP32_WIFI_NVS_ENABLED
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
#endif

std::string ip_address;
espp::WifiSta wifi_sta({.ssid = CONFIG_ESP_WIFI_SSID,
.password = CONFIG_ESP_WIFI_PASSWORD,
.num_connect_retries = CONFIG_ESP_MAXIMUM_RETRY,
.on_connected = nullptr,
.on_disconnected = nullptr,
.on_got_ip = [&ip_address](ip_event_got_ip_t *eventdata) {
ip_address = fmt::format("{}.{}.{}.{}", IP2STR(&eventdata->ip_info.ip));
fmt::print("got IP: {}\n", ip_address);
}});

while (!wifi_sta.is_connected()) {
std::this_thread::sleep_for(100ms);
}

//! [rtsp_server_example]
const int server_port = CONFIG_RTSP_SERVER_PORT;
const std::string server_uri = fmt::format("rtsp://{}:{}/mjpeg/1", ip_address, server_port);

logger.info("Starting RTSP Server on port {}", server_port);
logger.info("RTSP URI: {}", server_uri);

espp::RtspServer rtsp_server({
.server_address = ip_address,
.port = server_port,
.path = "/mjpeg/1",
.log_level = espp::Logger::Verbosity::INFO,
});
rtsp_server.start();

espp::JpegFrame jpeg_frame(jpeg_data, sizeof(jpeg_data));

logger.info("Parsed JPEG image, num bytes: {}", jpeg_frame.get_data().size());
logger.info("Created frame of size {}x{}", jpeg_frame.get_width(), jpeg_frame.get_height());
rtsp_server.send_frame(jpeg_frame);
//! [rtsp_server_example]

//! [rtsp_client_example]
espp::RtspClient rtsp_client({
.server_address = ip_address, // string of the form {}.{}.{}.{}
.rtsp_port = CONFIG_RTSP_SERVER_PORT,
.path = "/mjpeg/1",
.on_jpeg_frame = [](std::unique_ptr<espp::JpegFrame> jpeg_frame) {
fmt::print("Got JPEG frame of size {}x{}\n", jpeg_frame->get_width(), jpeg_frame->get_height());
},
.log_level = espp::Logger::Verbosity::ERROR,
});

std::error_code ec;

do {
// clear the error code
ec.clear();
rtsp_client.connect(ec);
if (ec) {
logger.error("Error connecting to server: {}", ec.message());
logger.info("Retrying in 1s...");
std::this_thread::sleep_for(1s);
}
} while (ec);

rtsp_client.describe(ec);
if (ec) {
logger.error("Error describing server: {}", ec.message());
}

rtsp_client.setup(ec);
if (ec) {
logger.error("Error setting up server: {}", ec.message());
}

rtsp_client.play(ec);
if (ec) {
logger.error("Error playing server: {}", ec.message());
}
//! [rtsp_client_example]

// now that both client and server are up, send frames forever
while (true) {
rtsp_server.send_frame(jpeg_frame);
std::this_thread::sleep_for(100ms);
}
}
5 changes: 5 additions & 0 deletions components/rtsp/example/partitions.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size
nvs, data, nvs, 0x9000, 0x6000
phy_init, data, phy, 0xf000, 0x1000
factory, app, factory, 0x10000, 2M
littlefs, data, spiffs, , 2M
12 changes: 12 additions & 0 deletions components/rtsp/example/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Common ESP-related
#
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192

CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y

#
# Partition Table
#
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
Loading