mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2026-01-29 22:00:54 +03:00
Display for AirPlay / Bluetooth (still WIP)
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,17 @@ 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) {
|
||||
u32_t start, current, stop = 0;
|
||||
|
||||
|
||||
sscanf(p, "%*[^:]:%u/%u/%u", &start, ¤t, &stop);
|
||||
current = (current - start) / 44100;
|
||||
if (stop) stop = (stop - start) / 44100;
|
||||
LOG_INFO("[%p]: SET PARAMETER progress %u/%u %s", ctx, current, stop, p);
|
||||
@@ -636,15 +644,16 @@ 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);
|
||||
|
||||
@@ -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;
|
||||
raop_cmd_vcb_t cmd_handler_chain;
|
||||
|
||||
static void raop_volume_up(void) {
|
||||
raop_cmd(raop, RAOP_VOLUME_UP, NULL);
|
||||
@@ -77,6 +79,51 @@ const static actrls_t controls = {
|
||||
raop_prev, raop_next, // prev, next
|
||||
};
|
||||
|
||||
/****************************************************************************************
|
||||
* Command handler
|
||||
*/
|
||||
bool cmd_handler(raop_event_t event, ...) {
|
||||
bool res = true;
|
||||
va_list args;
|
||||
|
||||
va_start(args, event);
|
||||
|
||||
switch(event) {
|
||||
case RAOP_SETUP:
|
||||
displayer_control(DISPLAYER_ACTIVATE);
|
||||
res = cmd_handler_chain(event, args);
|
||||
break;
|
||||
case RAOP_STOP:
|
||||
displayer_control(DISPLAYER_SUSPEND);
|
||||
res = cmd_handler_chain(event, args);
|
||||
break;
|
||||
case RAOP_METADATA: {
|
||||
int speed;
|
||||
char *artist = va_arg(args, char*), *album = va_arg(args, char*), *title = va_arg(args, char*);
|
||||
char *string = config_metadata_format(artist, album, title, &speed, 256);
|
||||
displayer_scroll(string, speed);
|
||||
free(string);
|
||||
break;
|
||||
}
|
||||
case RAOP_PROGRESS: {
|
||||
u32_t elapsed = va_arg(args, u32_t);
|
||||
u32_t duration = va_arg(args, u32_t);
|
||||
char msg[32];
|
||||
|
||||
if (elapsed > 3600) snprintf(msg, 32, "AIRPLAY %2u:%02u:%02u", elapsed / 3600, elapsed / 60, elapsed % 60);
|
||||
else snprintf(msg, 32, "AIRPLAY %2u:%02u", elapsed / 60, elapsed % 60);
|
||||
display->line(1, DISPLAY_LEFT, 0, DISPLAY_CLEAR | DISPLAY_UPDATE, msg);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = cmd_handler_chain(event, args);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Airplay taking/giving audio system's control
|
||||
*/
|
||||
@@ -96,7 +143,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 +170,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 +179,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,20 +10,22 @@
|
||||
#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)
|
||||
|
||||
@@ -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