diff --git a/.gitmodules b/.gitmodules index eb2e7f8..e5f1956 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "components/jpegdec"] path = components/jpegdec url = git@github.com:bitbank2/JPEGDEC +[submodule "components/esp-protocols"] + path = components/esp-protocols + url = git@github.com:espressif/esp-protocols diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bed369..7d1d8ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,13 +7,14 @@ include($ENV{IDF_PATH}/tools/cmake/project.cmake) # add the component directories that we want to use set(EXTRA_COMPONENT_DIRS "components/espp/components" + "components/esp-protocols/components" ) add_compile_definitions(BOARD_HAS_PSRAM) set( COMPONENTS - "main esptool_py esp_psram jpegdec task format monitor display_drivers wifi socket rtsp" + "main esptool_py esp_psram jpegdec task format monitor display_drivers wifi socket rtsp mdns" CACHE STRING "List of components to include" ) diff --git a/components/esp-protocols b/components/esp-protocols new file mode 160000 index 0000000..5143f5a --- /dev/null +++ b/components/esp-protocols @@ -0,0 +1 @@ +Subproject commit 5143f5ac01f27b669add28c80ac809b023d2cb1f diff --git a/components/espp b/components/espp index 13e6595..da6c92e 160000 --- a/components/espp +++ b/components/espp @@ -1 +1 @@ -Subproject commit 13e6595fb7588956ad774b1c22b67e5727040592 +Subproject commit da6c92e24cdf2eab37d7736a76a406c029879f23 diff --git a/main/main.cpp b/main/main.cpp index cc8ed5d..62865b6 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -7,14 +7,14 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_heap_caps.h" -#include "hal/spi_types.h" #include "driver/gpio.h" #include "driver/i2c.h" #include "driver/spi_master.h" +#include "esp_heap_caps.h" +#include "hal/spi_types.h" +#include "mdns.h" #include "nvs_flash.h" -// #include "jpeg_decoder.h" #include "jpegdec.h" #include "format.hpp" @@ -30,6 +30,9 @@ using namespace std::chrono_literals; +void mdns_print_results(mdns_result_t * results); +bool find_mdns_service(const char * service_name, const char * proto, std::string& host, int& port); + // function for drawing the minimum compressible units int drawMCUs(JPEGDRAW *pDraw) { int iCount = pDraw->iWidth * pDraw->iHeight; @@ -84,6 +87,37 @@ extern "C" void app_main(void) { std::this_thread::sleep_for(1s); } + // initialize mDNS + logger.info("Initializing mDNS"); + auto err = mdns_init(); + if (err != ESP_OK) { + logger.error("Could not initialize mDNS: {}", err); + return; + } + + uint8_t mac[6]; + esp_read_mac(mac, ESP_MAC_WIFI_STA); + std::string hostname = fmt::format("camera-display-{:x}{:x}{:x}", mac[3], mac[4], mac[5]); + err = mdns_hostname_set(hostname.c_str()); + if (err != ESP_OK) { + logger.error("Could not set mDNS hostname: {}", err); + return; + } + logger.info("mDNS hostname set to '{}'", hostname); + err = mdns_instance_name_set("Camera Display"); + if (err != ESP_OK) { + logger.error("Could not set mDNS instance name: {}", err); + return; + } + std::string mdns_service_address; + int mdns_service_port; + bool found_mdns_server{false}; + while (!found_mdns_server) { + logger.info("Searching for RTSP server..."); + found_mdns_server = find_mdns_service("_rtsp", "_tcp", mdns_service_address, mdns_service_port); + } + logger.info("Found RTSP server: {}:{}", mdns_service_address, mdns_service_port); + std::mutex jpeg_mutex; std::condition_variable jpeg_cv; static constexpr size_t MAX_JPEG_FRAMES = 2; @@ -142,8 +176,8 @@ extern "C" void app_main(void) { logger.info("Starting server task"); std::atomic num_frames_received{0}; espp::RtspClient rtsp_client({ - .server_address = "192.168.86.216", - .rtsp_port = 8554, + .server_address = mdns_service_address, + .rtsp_port = mdns_service_port, .path = "/mjpeg/1", .on_jpeg_frame = [&jpeg_mutex, &jpeg_cv, &jpeg_frames, &num_frames_received](std::unique_ptr jpeg_frame) { { @@ -202,3 +236,73 @@ extern "C" void app_main(void) { std::this_thread::sleep_for(1s); } } + +static const char * ip_protocol_str[] = {"V4", "V6", "MAX"}; + +void mdns_print_results(mdns_result_t * results) { + mdns_result_t *r = results; + mdns_ip_addr_t *a = NULL; + int i = 1, t; + while (r) { + if (r->esp_netif) { + printf("%d: Interface: %s, Type: %s, TTL: %lu\n", i++, esp_netif_get_ifkey(r->esp_netif), + ip_protocol_str[r->ip_protocol], r->ttl); + } + if (r->instance_name) { + printf(" PTR : %s.%s.%s\n", r->instance_name, r->service_type, r->proto); + } + if (r->hostname) { + printf(" SRV : %s.local:%u\n", r->hostname, r->port); + } + if (r->txt_count) { + printf(" TXT : [%zu] ", r->txt_count); + for (t = 0; t < r->txt_count; t++) { + printf("%s=%s(%d); ", r->txt[t].key, r->txt[t].value ? r->txt[t].value : "NULL", r->txt_value_len[t]); + } + printf("\n"); + } + a = r->addr; + while (a) { + if (a->addr.type == ESP_IPADDR_TYPE_V6) { + printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); + } else { + printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); + } + a = a->next; + } + r = r->next; + } +} + +bool find_mdns_service(const char * service_name, const char * proto, std::string& host, int& port) { + fmt::print("Query PTR: {}.{}.local\n", service_name, proto); + + mdns_result_t * results = NULL; + int timeout = 3000; + int max_results = 20; + esp_err_t err = mdns_query_ptr(service_name, proto, timeout, max_results, &results); + if(err){ + fmt::print("Query Failed\n"); + return false; + } + if(!results){ + fmt::print("No results found!\n"); + return false; + } + + mdns_print_results(results); + // now set the host ip address string and port number from the results + mdns_result_t * r = results; + if (r->addr) { + if (r->addr->addr.type == ESP_IPADDR_TYPE_V6) { + host = fmt::format(IPV6STR, IPV62STR(r->addr->addr.u_addr.ip6)); + } else { + host = fmt::format("{}.{}.{}.{}", IP2STR(&(r->addr->addr.u_addr.ip4))); + } + } + if (r->port) { + port = r->port; + } + mdns_query_results_free(results); + return true; +}