use network manager events for AirPlay and Spotify

- split network_manager.h in two parts
- centralize mDNS
This commit is contained in:
Philippe G
2021-12-22 18:41:49 -08:00
parent d914e68a9b
commit dc1e258d64
12 changed files with 128 additions and 188 deletions

View File

@@ -1,7 +1,7 @@
idf_component_register(SRC_DIRS .
INCLUDE_DIRS .
PRIV_REQUIRES newlib freertos pthread platform_config mdns services codecs tools display
PRIV_REQUIRES newlib freertos pthread platform_config mdns services codecs tools display wifi-manager
)
set_source_files_properties(raop.c

View File

@@ -111,7 +111,7 @@ extern char private_key[];
static void on_dmap_string(void *ctx, const char *code, const char *name, const char *buf, size_t len);
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
struct raop_ctx_s *raop_create(uint32_t host, char *name,
unsigned char mac[6], int latency,
raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb) {
@@ -150,7 +150,7 @@ struct raop_ctx_s *raop_create(struct in_addr host, char *name,
memset(ctx, 0, sizeof(raop_ctx_t));
#ifdef WIN32
ctx->svr = glmDNSServer;
ctx->svr = glmDNSServer;
#endif
ctx->host.s_addr = host;
ctx->sock = socket(AF_INET, SOCK_STREAM, 0);
@@ -162,7 +162,7 @@ struct raop_ctx_s *raop_create(struct in_addr host, char *name,
free(ctx);
return NULL;
}
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = host;
addr.sin_family = AF_INET;
@@ -196,7 +196,7 @@ struct raop_ctx_s *raop_create(struct in_addr host, char *name,
id[63] = '\0';
ctx->svc = mdnsd_register_svc(ctx->svr, id, "_raop._tcp.local", ctx->port, NULL, (const char**) txt);
pthread_create(&ctx->thread, NULL, &rtsp_thread, ctx);
#else
LOG_INFO("starting mDNS with %s", id);
ESP_ERROR_CHECK( mdns_service_add(id, "_raop", "_tcp", ctx->port, txt, sizeof(txt) / sizeof(mdns_txt_item_t)) );

View File

@@ -11,7 +11,7 @@
#include "platform.h"
#include "raop_sink.h"
struct raop_ctx_s* raop_create(struct in_addr host, char *name, unsigned char mac[6], int latency,
struct raop_ctx_s* raop_create(uint32_t host, char *name, unsigned char mac[6], int latency,
raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb);
void raop_delete(struct raop_ctx_s *ctx);
void raop_abort(struct raop_ctx_s *ctx);

View File

@@ -3,7 +3,6 @@
#include <ctype.h>
#include <stdlib.h>
#include "mdns.h"
#include "nvs.h"
#include "esp_netif.h"
#include "esp_log.h"
@@ -17,6 +16,7 @@
#include "display.h"
#include "accessors.h"
#include "log_util.h"
#include "network_services.h"
#ifndef CONFIG_AIRPLAY_NAME
#define CONFIG_AIRPLAY_NAME "ESP32-AirPlay"
@@ -148,77 +148,36 @@ static bool cmd_handler(raop_event_t event, ...) {
*/
void raop_sink_deinit(void) {
raop_delete(raop);
mdns_free();
}
/****************************************************************************************
* Airplay sink startup
*/
static bool raop_sink_start(raop_cmd_vcb_t cmd_cb, raop_data_cb_t data_cb) {
const char *hostname = NULL;
char sink_name[64-6] = CONFIG_AIRPLAY_NAME;
tcpip_adapter_ip_info_t ipInfo = { };
struct in_addr host;
tcpip_adapter_if_t ifs[] = { TCPIP_ADAPTER_IF_ETH, TCPIP_ADAPTER_IF_STA, TCPIP_ADAPTER_IF_AP };
// get various IP info
// it is possible to get the currently active interface with the following call:
// network_get_active_interface()
for (int i = 0; i < sizeof(ifs) / sizeof(tcpip_adapter_if_t); i++)
if (tcpip_adapter_get_ip_info(ifs[i], &ipInfo) == ESP_OK && ipInfo.ip.addr != IPADDR_ANY) {
tcpip_adapter_get_hostname(ifs[i], &hostname);
break;
}
if (!hostname) {
LOG_INFO( "no hostname/IP found, can't start AirPlay");
return false;
}
host.s_addr = ipInfo.ip.addr;
// initialize mDNS
ESP_ERROR_CHECK( mdns_init() );
ESP_ERROR_CHECK( mdns_hostname_set(hostname) );
char * sink_name_buffer= (char *)config_alloc_get(NVS_TYPE_STR,"airplay_name");
if (sink_name_buffer != NULL){
memset(sink_name, 0x00, sizeof(sink_name));
strncpy(sink_name,sink_name_buffer,sizeof(sink_name)-1 );
free(sink_name_buffer);
}
LOG_INFO( "mdns hostname for ip %s set to: [%s] with servicename %s", inet_ntoa(host), hostname, sink_name);
// create RAOP instance, latency is set by controller
static void raop_sink_start(nm_state_t state_id, int sub_state) {
esp_netif_t* netif;
esp_netif_ip_info_t ipInfo = { };
uint8_t mac[6];
esp_read_mac(mac, ESP_MAC_WIFI_STA);
cmd_handler_chain = cmd_cb;
raop = raop_create(host, sink_name, mac, 0, cmd_handler, data_cb);
return true;
}
char* sink_name = (char*) config_alloc_get_default(NVS_TYPE_STR, "airplay_name", CONFIG_AIRPLAY_NAME, 0);
/****************************************************************************************
* Airplay sink timer handler
*/
static void raop_start_handler( TimerHandle_t xTimer ) {
if (raop_sink_start(raop_cbs.cmd, raop_cbs.data)) {
xTimerDelete(xTimer, portMAX_DELAY);
}
}
netif = network_get_active_interface();
esp_netif_get_ip_info(netif, &ipInfo);
esp_netif_get_mac(netif, mac);
cmd_handler_chain = raop_cbs.cmd;
LOG_INFO( "Starting Airplay for ip %s with servicename %s", inet_ntoa(ipInfo.ip.addr), sink_name);
raop = raop_create(ipInfo.ip.addr, sink_name, mac, 0, cmd_handler, raop_cbs.data);
free(sink_name);
}
/****************************************************************************************
* Airplay sink initialization
*/
void raop_sink_init(raop_cmd_vcb_t cmd_cb, raop_data_cb_t data_cb) {
if (!raop_sink_start(cmd_cb, data_cb)) {
raop_cbs.cmd = cmd_cb;
raop_cbs.data = data_cb;
TimerHandle_t timer = xTimerCreate("raopStart", 5000 / portTICK_RATE_MS, pdTRUE, NULL, raop_start_handler);
xTimerStart(timer, portMAX_DELAY);
LOG_INFO( "Delaying AirPlay start");
}
raop_cbs.cmd = cmd_cb;
raop_cbs.data = data_cb;
network_register_state_callback(NETWORK_WIFI_ACTIVE_STATE, WIFI_CONNECTED_STATE, "raop_sink_start", raop_sink_start);
network_register_state_callback(NETWORK_ETH_ACTIVE_STATE, ETH_ACTIVE_CONNECTED_STATE, "raop_sink_start", raop_sink_start);
}
/****************************************************************************************

View File

@@ -84,7 +84,7 @@ static void common_task_init(void) {
if (!common_queue_set) {
common_queue_set = xQueueCreateSet(BUTTON_QUEUE_LEN + 1);
xTaskCreateStatic( (TaskFunction_t) buttons_task, "buttons_thread", BUTTON_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 2, xStack, &xTaskBuffer);
xTaskCreateStatic( (TaskFunction_t) buttons_task, "buttons", BUTTON_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 2, xStack, &xTaskBuffer);
}
}

View File

@@ -104,7 +104,7 @@ static void cspotTask(void *pvParameters) {
session->connectWithRandomAp();
auto token = session->authenticate(cspot.blob);
ESP_LOGI(TAG, "Creating Spotify(CSpot) player");
ESP_LOGI(TAG, "Creating Spotify (using CSpot) player");
// Auth successful
if (token.size() > 0 && cspot.cHandler(CSPOT_SETUP, 44100)) {

View File

@@ -59,8 +59,6 @@ void ZeroconfAuthenticator::registerZeroconf()
const char* service = "_spotify-connect._tcp";
#ifdef ESP_PLATFORM
mdns_init();
mdns_hostname_set("cspot");
mdns_txt_item_t serviceTxtData[3] = {
{"VERSION", "1.0"},
{"CPath", "/spotify_info"},

View File

@@ -3,19 +3,16 @@
#include <ctype.h>
#include <stdlib.h>
#include "mdns.h"
#include "nvs.h"
#include "tcpip_adapter.h"
// IDF-V4++ #include "esp_netif.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_pthread.h"
#include "esp_system.h"
#include "freertos/timers.h"
#include "platform_config.h"
#include "audio_controls.h"
#include "display.h"
#include "accessors.h"
#include "network_services.h"
#include "cspot_private.h"
#include "cspot_sink.h"
@@ -138,59 +135,28 @@ static bool cmd_handler(cspot_event_t event, ...) {
return true;
}
/****************************************************************************************
* CSpot sink de-initialization
*/
void cspot_sink_deinit(void) {
mdns_free();
}
/****************************************************************************************
* CSpot sink startup
*/
static bool cspot_sink_start(cspot_cmd_vcb_t cmd_cb, cspot_data_cb_t data_cb) {
const char *hostname = NULL;
tcpip_adapter_ip_info_t ipInfo = { };
tcpip_adapter_if_t ifs[] = { TCPIP_ADAPTER_IF_ETH, TCPIP_ADAPTER_IF_STA, TCPIP_ADAPTER_IF_AP };
// get various IP info
for (int i = 0; i < sizeof(ifs) / sizeof(tcpip_adapter_if_t); i++)
if (tcpip_adapter_get_ip_info(ifs[i], &ipInfo) == ESP_OK && ipInfo.ip.addr != IPADDR_ANY) {
tcpip_adapter_get_hostname(ifs[i], &hostname);
break;
}
if (!hostname) {
ESP_LOGI(TAG, "No hostname/IP found, can't start CSpot (will retry)");
return false;
}
cmd_handler_chain = cmd_cb;
cspot = cspot_create(hostname, cmd_handler, data_cb);
return true;
}
static void cspot_sink_start(nm_state_t state_id, int sub_state) {
const char *hostname;
/****************************************************************************************
* CSpot sink timer handler
*/
static void cspot_start_handler( TimerHandle_t xTimer ) {
if (cspot_sink_start(cspot_cbs.cmd, cspot_cbs.data)) {
xTimerDelete(xTimer, portMAX_DELAY);
}
}
cmd_handler_chain = cspot_cbs.cmd;
network_get_hostname(&hostname);
ESP_LOGI(TAG, "Starting Spotify (CSpot) servicename %s", hostname);
cspot = cspot_create(hostname, cmd_handler, cspot_cbs.data);
}
/****************************************************************************************
* CSpot sink initialization
*/
void cspot_sink_init(cspot_cmd_vcb_t cmd_cb, cspot_data_cb_t data_cb) {
if (!cspot_sink_start(cmd_cb, data_cb)) {
cspot_cbs.cmd = cmd_cb;
cspot_cbs.data = data_cb;
TimerHandle_t timer = xTimerCreate("cspotStart", 5000 / portTICK_RATE_MS, pdTRUE, NULL, cspot_start_handler);
xTimerStart(timer, portMAX_DELAY);
ESP_LOGI(TAG, "Delaying CSPOT start");
}
cspot_cbs.cmd = cmd_cb;
cspot_cbs.data = data_cb;
network_register_state_callback(NETWORK_WIFI_ACTIVE_STATE, WIFI_CONNECTED_STATE, "cspot_sink_start", cspot_sink_start);
network_register_state_callback(NETWORK_ETH_ACTIVE_STATE, ETH_ACTIVE_CONNECTED_STATE, "cspot_sink_start", cspot_sink_start);
}
/****************************************************************************************

View File

@@ -32,7 +32,7 @@ void cspot_sink_init(cspot_cmd_vcb_t cmd_cb, cspot_data_cb_t data_cb);
/**
* @brief deinit sink mode (need to be provided)
*/
void cspot_sink_deinit(void);
#define cspot_sink_deinit()
/**
* @brief force disconnection

View File

@@ -9,74 +9,12 @@
#include "freertos/event_groups.h"
#include "hsm.h"
#include "esp_log.h"
#include "network_services.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* --------------------- ENUMERATION ---------------------
*/
//#define ADD_ROOT(NAME, HANDLER, ENTRY, EXIT, CHILD)
//#define ADD_ROOT(NAME, HANDLER, ENTRY, EXIT, CHILD)
//#define ADD_LEAF(NAME, HANDLER, ENTRY, EXIT, PARENT, LEVEL)
#define ALL_NM_STATE \
ADD_ROOT_LEAF(NETWORK_INSTANTIATED_STATE)\
ADD_ROOT_LEAF(NETWORK_INITIALIZING_STATE)\
ADD_ROOT(NETWORK_ETH_ACTIVE_STATE, Eth_Active_State)\
ADD_ROOT(NETWORK_WIFI_ACTIVE_STATE, Wifi_Active_State)\
ADD_ROOT(NETWORK_WIFI_CONFIGURING_ACTIVE_STATE, Wifi_Configuring_State)
#define ALL_ETH_STATE(PARENT, LEVEL)\
ADD_LEAF(ETH_STARTING_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_LINKUP_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_LINKDOWN_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_CONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_CONNECTING_NEW_STATE,PARENT,LEVEL)
#define ALL_WIFI_STATE(PARENT, LEVEL)\
ADD_LEAF(WIFI_INITIALIZING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_NEW_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_NEW_FAILED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_USER_DISCONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_LOST_CONNECTION_STATE,PARENT,LEVEL)
#define ALL_WIFI_CONFIGURING_STATE(PARENT, LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_SUCCESS_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_SUCCESS_GOTOSTA_STATE,PARENT,LEVEL)
#define ADD_ROOT(name, ...) name,
#define ADD_ROOT_LEAF(name, ...) name,
#define ADD_LEAF(name, ...) name,
typedef enum {
ALL_NM_STATE
TOTAL_NM_STATE
} nm_state_t;
typedef enum {
ALL_WIFI_STATE(,)
TOTAL_WIFI_ACTIVE_STATE
} mn_wifi_active_state_t;
typedef enum {
ALL_ETH_STATE(,)
TOTAL_ETH_ACTIVE_STATE
} mn_eth_active_state_t;
typedef enum {
ALL_WIFI_CONFIGURING_STATE(,)
TOTAL_WIFI_CONFIGURING_STATE
} mn_wifi_configuring_state_t;
#undef ADD_STATE
#undef ADD_ROOT
#undef ADD_ROOT_LEAF
#undef ADD_LEAF
typedef void (*network_status_reached_cb)(nm_state_t state_id, int sub_state );
//! List of oven events
#define ALL_NM_EVENTS \
ADD_FIRST_EVENT(EN_LINK_UP) \
@@ -369,11 +307,7 @@ void network_manager_initialise_mdns();
/**
* @brief Register a callback to a custom function when specific network manager states are reached.
*/
esp_err_t network_register_state_callback(nm_state_t state, int sub_state, const char* from, network_status_reached_cb cb);
bool network_is_wifi_prioritized();
esp_netif_t * network_get_active_interface();
esp_err_t network_get_hostname( const char **hostname);
esp_err_t network_get_ip_info(tcpip_adapter_ip_info_t* ipInfo);
void network_set_timer(uint16_t duration);
void network_set_hostname(esp_netif_t * netif);
esp_err_t network_get_ip_info_for_netif(esp_netif_t* netif, tcpip_adapter_ip_info_t* ipInfo);

View File

@@ -0,0 +1,75 @@
#pragma once
#include "esp_netif.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ADD_ROOT(name, ...) name,
#define ADD_ROOT_LEAF(name, ...) name,
#define ADD_LEAF(name, ...) name,
#define ALL_NM_STATE \
ADD_ROOT_LEAF(NETWORK_INSTANTIATED_STATE)\
ADD_ROOT_LEAF(NETWORK_INITIALIZING_STATE)\
ADD_ROOT(NETWORK_ETH_ACTIVE_STATE, Eth_Active_State)\
ADD_ROOT(NETWORK_WIFI_ACTIVE_STATE, Wifi_Active_State)\
ADD_ROOT(NETWORK_WIFI_CONFIGURING_ACTIVE_STATE, Wifi_Configuring_State)
#define ALL_ETH_STATE(PARENT, LEVEL)\
ADD_LEAF(ETH_STARTING_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_LINKUP_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_LINKDOWN_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_CONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_CONNECTING_NEW_STATE,PARENT,LEVEL)
#define ALL_WIFI_STATE(PARENT, LEVEL)\
ADD_LEAF(WIFI_INITIALIZING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_NEW_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_NEW_FAILED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_USER_DISCONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_LOST_CONNECTION_STATE,PARENT,LEVEL)
#define ALL_WIFI_CONFIGURING_STATE(PARENT, LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_SUCCESS_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_SUCCESS_GOTOSTA_STATE,PARENT,LEVEL)
typedef enum {
ALL_NM_STATE
TOTAL_NM_STATE
} nm_state_t;
typedef enum {
ALL_WIFI_STATE(,)
TOTAL_WIFI_ACTIVE_STATE
} mn_wifi_active_state_t;
typedef enum {
ALL_ETH_STATE(,)
TOTAL_ETH_ACTIVE_STATE
} mn_eth_active_state_t;
typedef enum {
ALL_WIFI_CONFIGURING_STATE(,)
TOTAL_WIFI_CONFIGURING_STATE
} mn_wifi_configuring_state_t;
#undef ADD_STATE
#undef ADD_ROOT
#undef ADD_ROOT_LEAF
#undef ADD_LEAF
typedef void (*network_status_reached_cb)(nm_state_t state_id, int sub_state);
esp_err_t network_register_state_callback(nm_state_t state, int sub_state, const char* from, network_status_reached_cb cb);
esp_netif_t * network_get_active_interface();
esp_err_t network_get_hostname(const char **hostname);
esp_err_t network_get_ip_info(tcpip_adapter_ip_info_t* ipInfo);
#ifdef __cplusplus
}
#endif

View File

@@ -76,6 +76,7 @@ const char * str_or_null(const char * str) { return (str?str:null_string_placeho
bool is_recovery_running;
void cb_connection_got_ip(nm_state_t new_state, int sub_state){
const char *hostname;
static ip4_addr_t ip;
tcpip_adapter_ip_info_t ipInfo;
network_get_ip_info(&ipInfo);
@@ -86,11 +87,18 @@ void cb_connection_got_ip(nm_state_t new_state, int sub_state){
}
esp_restart();
}
ip.addr = ipInfo.ip.addr;
ESP_LOGI(TAG, "Network connected!");
// initializing mDNS
network_get_hostname(&hostname);
mdns_init();
mdns_hostname_set(hostname);
ESP_LOGI(TAG, "Network connected and mDNS initialized with %s", hostname);
messaging_post_message(MESSAGING_INFO,MESSAGING_CLASS_SYSTEM,"Network connected");
xEventGroupSetBits(network_event_group, CONNECTED_BIT);
bNetworkConnected=true;
led_unpush(LED_GREEN);
if(is_recovery_running){
// when running in recovery, send a LMS discovery message