mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-08 12:37:01 +03:00
Merge remote-tracking branch 'origin/master' into httpd
This commit is contained in:
@@ -532,7 +532,7 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
|
||||
ctx->active_remote.thread = xTaskCreateStatic( (TaskFunction_t) search_remote, "search_remote", SEARCH_STACK_SIZE, ctx, ESP_TASK_PRIO_MIN + 1, ctx->active_remote.xStack, ctx->active_remote.xTaskBuffer);
|
||||
#endif
|
||||
|
||||
} else if (!strcmp(method, "SETUP") && ((buf = kd_lookup(headers, "Transport")) != NULL)) {
|
||||
} else if (!strcmp(method, "SETUP") && ((buf = kd_lookup(headers, "Transport")) != NULL)) {
|
||||
char *p;
|
||||
rtp_resp_t rtp = { 0 };
|
||||
short unsigned tport = 0, cport = 0;
|
||||
@@ -571,7 +571,7 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
|
||||
kd_add(resp, "Audio-Latency", latency);
|
||||
}
|
||||
|
||||
buf = kd_lookup(headers, "RTP-Info");
|
||||
buf = kd_lookup(headers, "RTP-Info");
|
||||
if (buf && (p = strcasestr(buf, "seq")) != NULL) sscanf(p, "%*[^=]=%hu", &seqno);
|
||||
if (buf && (p = strcasestr(buf, "rtptime")) != NULL) sscanf(p, "%*[^=]=%u", &rtptime);
|
||||
|
||||
@@ -584,7 +584,7 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
|
||||
unsigned rtptime = 0;
|
||||
char *p;
|
||||
|
||||
buf = kd_lookup(headers, "RTP-Info");
|
||||
buf = kd_lookup(headers, "RTP-Info");
|
||||
if ((p = strcasestr(buf, "seq")) != NULL) sscanf(p, "%*[^=]=%hu", &seqno);
|
||||
if ((p = strcasestr(buf, "rtptime")) != NULL) sscanf(p, "%*[^=]=%u", &rtptime);
|
||||
|
||||
@@ -615,7 +615,7 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
|
||||
|
||||
LOG_INFO("[%p]: mDNS search task terminated", ctx);
|
||||
#endif
|
||||
|
||||
|
||||
memset(&ctx->active_remote, 0, sizeof(ctx->active_remote));
|
||||
NFREE(ctx->rtsp.aeskey);
|
||||
NFREE(ctx->rtsp.aesiv);
|
||||
@@ -626,9 +626,18 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
|
||||
} else if (!strcmp(method, "SET_PARAMETER")) {
|
||||
char *p;
|
||||
|
||||
if (body && (p = strcasestr(body, "volume")) != NULL) {
|
||||
if (body && (p = strcasestr(body, "volume")) != NULL) {
|
||||
float volume;
|
||||
|
||||
sscanf(p, "%*[^:]:%f", &volume);
|
||||
LOG_INFO("[%p]: SET PARAMETER volume %f", ctx, volume);
|
||||
volume = (volume == -144.0) ? 0 : (1 + volume / 30);
|
||||
success = ctx->cmd_cb(RAOP_VOLUME, volume);
|
||||
} else if (body && (p = strcasestr(body, "progress")) != NULL) {
|
||||
int start, current, stop = 0;
|
||||
|
||||
sscanf(p, "%*[^:]:%u/%u/%u", &start, ¤t, &stop);
|
||||
|
||||
current = (current - start) / 44100;
|
||||
if (stop) stop = (stop - start) / 44100;
|
||||
else stop = -1;
|
||||
LOG_INFO("[%p]: SET PARAMETER progress %u/%u %s", ctx, current, stop, p);
|
||||
@@ -636,23 +645,28 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
|
||||
}
|
||||
|
||||
if (body && ((p = kd_lookup(headers, "Content-Type")) != NULL) && !strcasecmp(p, "application/x-dmap-tagged")) {
|
||||
struct metadata_s metadata;
|
||||
dmap_settings settings = {
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, on_dmap_string, NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
LOG_INFO("[%p]: received metadata");
|
||||
settings.ctx = &metadata;
|
||||
memset(&metadata, 0, sizeof(struct metadata_s));
|
||||
if (!dmap_parse(&settings, body, len)) {
|
||||
if (!dmap_parse(&settings, body, len)) {
|
||||
LOG_INFO("[%p]: received metadata\n\tartist: %s\n\talbum: %s\n\ttitle: %s",
|
||||
ctx, metadata.artist, metadata.album, metadata.title);
|
||||
success = ctx->cmd_cb(RAOP_METADATA, metadata.artist, metadata.album, metadata.title);
|
||||
free_metadata(&metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// don't need to free "buf" because kd_lookup return a pointer, not a strdup
|
||||
kd_add(resp, "Audio-Jack-Status", "connected; type=analog");
|
||||
kd_add(resp, "CSeq", kd_lookup(headers, "CSeq"));
|
||||
|
||||
if (success) {
|
||||
buf = http_send(sock, "RTSP/1.0 200 OK", resp);
|
||||
} else {
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
#include "config.h"
|
||||
#include "raop.h"
|
||||
#include "audio_controls.h"
|
||||
#include "display.h"
|
||||
#include "accessors.h"
|
||||
|
||||
#include "log_util.h"
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
#ifndef CONFIG_AIRPLAY_NAME
|
||||
@@ -28,6 +29,7 @@ log_level util_loglevel;
|
||||
|
||||
static log_level *loglevel = &raop_loglevel;
|
||||
static struct raop_ctx_s *raop;
|
||||
static raop_cmd_vcb_t cmd_handler_chain;
|
||||
|
||||
static void raop_volume_up(void) {
|
||||
raop_cmd(raop, RAOP_VOLUME_UP, NULL);
|
||||
@@ -78,11 +80,52 @@ const static actrls_t controls = {
|
||||
};
|
||||
|
||||
/****************************************************************************************
|
||||
* Airplay taking/giving audio system's control
|
||||
* Command handler
|
||||
*/
|
||||
void raop_master(bool on) {
|
||||
if (on) actrls_set(controls, NULL);
|
||||
else actrls_unset();
|
||||
static bool cmd_handler(raop_event_t event, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, event);
|
||||
|
||||
// handle audio event and stop if forbidden
|
||||
if (!cmd_handler_chain(event, args)) {
|
||||
va_end(args);
|
||||
return false;
|
||||
}
|
||||
|
||||
// now handle events for display
|
||||
switch(event) {
|
||||
case RAOP_SETUP:
|
||||
actrls_set(controls, NULL);
|
||||
displayer_control(DISPLAYER_ACTIVATE, "AIRPLAY");
|
||||
break;
|
||||
case RAOP_PLAY:
|
||||
displayer_control(DISPLAYER_TIMER_RUN);
|
||||
break;
|
||||
case RAOP_FLUSH:
|
||||
displayer_control(DISPLAYER_TIMER_PAUSE);
|
||||
break;
|
||||
case RAOP_STOP:
|
||||
actrls_unset();
|
||||
displayer_control(DISPLAYER_SUSPEND);
|
||||
break;
|
||||
case RAOP_METADATA: {
|
||||
char *artist = va_arg(args, char*), *album = va_arg(args, char*), *title = va_arg(args, char*);
|
||||
displayer_metadata(artist, album, title);
|
||||
break;
|
||||
}
|
||||
case RAOP_PROGRESS: {
|
||||
int elapsed = va_arg(args, int), duration = va_arg(args, int);
|
||||
displayer_timer(DISPLAYER_ELAPSED, elapsed, duration);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
@@ -96,7 +139,7 @@ void raop_sink_deinit(void) {
|
||||
/****************************************************************************************
|
||||
* Airplay sink initialization
|
||||
*/
|
||||
void raop_sink_init(raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb) {
|
||||
void raop_sink_init(raop_cmd_vcb_t cmd_cb, raop_data_cb_t data_cb) {
|
||||
const char *hostname;
|
||||
char sink_name[64-6] = CONFIG_AIRPLAY_NAME;
|
||||
tcpip_adapter_ip_info_t ipInfo;
|
||||
@@ -123,7 +166,8 @@ void raop_sink_init(raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb) {
|
||||
// create RAOP instance, latency is set by controller
|
||||
uint8_t mac[6];
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
raop = raop_create(host, sink_name, mac, 0, cmd_cb, data_cb);
|
||||
cmd_handler_chain = cmd_cb;
|
||||
raop = raop_create(host, sink_name, mac, 0, cmd_handler, data_cb);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
@@ -131,6 +175,7 @@ void raop_sink_init(raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb) {
|
||||
*/
|
||||
void raop_disconnect(void) {
|
||||
LOG_INFO("forced disconnection");
|
||||
displayer_control(DISPLAYER_SHUTDOWN);
|
||||
raop_cmd(raop, RAOP_STOP, NULL);
|
||||
actrls_unset();
|
||||
}
|
||||
|
||||
@@ -10,31 +10,28 @@
|
||||
#define RAOP_SINK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define RAOP_SAMPLE_RATE 44100
|
||||
|
||||
typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_PAUSE, RAOP_STOP,
|
||||
typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_METADATA, RAOP_PROGRESS, RAOP_PAUSE, RAOP_STOP,
|
||||
RAOP_VOLUME, RAOP_TIMING, RAOP_PREV, RAOP_NEXT, RAOP_REW, RAOP_FWD,
|
||||
RAOP_VOLUME_UP, RAOP_VOLUME_DOWN, RAOP_RESUME, RAOP_TOGGLE } raop_event_t ;
|
||||
|
||||
typedef bool (*raop_cmd_cb_t)(raop_event_t event, void *param);
|
||||
typedef bool (*raop_cmd_cb_t)(raop_event_t event, ...);
|
||||
typedef bool (*raop_cmd_vcb_t)(raop_event_t event, va_list args);
|
||||
typedef void (*raop_data_cb_t)(const u8_t *data, size_t len, u32_t playtime);
|
||||
|
||||
/**
|
||||
* @brief init sink mode (need to be provided)
|
||||
*/
|
||||
void raop_sink_init(raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb);
|
||||
void raop_sink_init(raop_cmd_vcb_t cmd_cb, raop_data_cb_t data_cb);
|
||||
|
||||
/**
|
||||
* @brief deinit sink mode (need to be provided)
|
||||
*/
|
||||
void raop_sink_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief do what's necessary when becoming in charge
|
||||
*/
|
||||
void raop_master(bool on);
|
||||
|
||||
/**
|
||||
* @brief force disconnection
|
||||
*/
|
||||
|
||||
@@ -429,7 +429,7 @@ static void buffer_put_packet(rtp_t *ctx, seq_t seqno, unsigned rtptime, bool fi
|
||||
ctx->ab_read = seqno;
|
||||
ctx->flush_seqno = -1;
|
||||
ctx->playing = true;
|
||||
ctx->resent_req = ctx->resent_rec = ctx->silent_frames = ctx->discarded = 0;
|
||||
ctx->resent_req = ctx->resent_rec = ctx->silent_frames = ctx->discarded = 0;
|
||||
playtime = ctx->synchro.time + (((s32_t)(rtptime - ctx->synchro.rtp)) * 1000) / RAOP_SAMPLE_RATE;
|
||||
ctx->cmd_cb(RAOP_PLAY, playtime);
|
||||
} else {
|
||||
@@ -671,7 +671,7 @@ static void *rtp_thread_func(void *arg) {
|
||||
|
||||
if (!count--) {
|
||||
rtp_request_timing(ctx);
|
||||
count = 3;
|
||||
count = 3;
|
||||
}
|
||||
|
||||
if ((ctx->synchro.status & RTP_SYNC) && (ctx->synchro.status & NTP_SYNC)) ctx->cmd_cb(RAOP_TIMING);
|
||||
|
||||
@@ -47,11 +47,8 @@ typedef struct metadata_s {
|
||||
u8_t channels;
|
||||
} metadata_t;
|
||||
|
||||
/*
|
||||
void free_metadata(struct metadata_s *metadata);
|
||||
void dup_metadata(struct metadata_s *dst, struct metadata_s *src);
|
||||
*/
|
||||
|
||||
|
||||
u32_t gettime_ms(void);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user