static pthread_mutex_t dacp_server_information_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t dacp_server_information_cv = PTHREAD_COND_INITIALIZER;
-int dacp_send_command(const char *command, char **body, size_t *bodysize) {
+int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
// will malloc space for the body or set it to NULL -- the caller should free it.
return type;
}
-int32_t dacp_get_client_volume(rtsp_conn_info *conn) {
+int32_t dacp_get_client_volume(void) {
char *server_reply = NULL;
int32_t overall_volume = -1;
ssize_t reply_size;
int response =
dacp_send_command("getproperty?properties=dmcp.volume", &server_reply, &reply_size);
if (response == 200) { // if we get an okay
- uint32_t *np = (uint32_t *)server_reply;
- overall_volume = ntohl(*np);
- // debug(1,"Overall Volume is %d.",overall_volume);
+ char *sp = server_reply;
+ int32_t item_size;
+ if (reply_size >= 8) {
+ if (dacp_tlv_crawl(&sp, &item_size) == 'cmgt') {
+ debug(1,"Volume:",item_size);
+ sp -= item_size; // drop down into the array -- don't skip over it
+ reply_size -= 8;
+ while (reply_size >= 8) {
+ uint32_t type = dacp_tlv_crawl(&sp, &item_size);
+ reply_size -= item_size + 8;
+ if (type == 'cmvo') { // drop down into the dictionary -- don't skip over it
+ char *t = sp - item_size;
+ overall_volume = ntohl(*(int32_t *)(t));
+ }
+ }
+ } else {
+ debug(1,"Unexpected payload response from getproperty?properties=dmcp.volume");
+ }
+ } else {
+ debug(1,"Too short a response from getproperty?properties=dmcp.volume");
+ }
+ debug(1,"Overall Volume is %d.",overall_volume);
free(server_reply);
} else {
debug(1, "Unexpected response %d to dacp volume control request", response);
return overall_volume;
}
-int dacp_set_include_speaker_volume(rtsp_conn_info *conn, int64_t machine_number, int32_t vo) {
+int dacp_set_include_speaker_volume(int64_t machine_number, int32_t vo) {
char message[1000];
memset(message, 0, sizeof(message));
sprintf(message, "setproperty?include-speaker-id=%ld&dmcp.volume=%d", machine_number, vo);
// should return 204
}
-int dacp_set_speaker_volume(rtsp_conn_info *conn, int64_t machine_number, int32_t vo) {
+int dacp_set_speaker_volume(int64_t machine_number, int32_t vo) {
char message[1000];
memset(message, 0, sizeof(message));
sprintf(message, "setproperty?speaker-id=%ld&dmcp.volume=%d", machine_number, vo);
// should return 204
}
-int dacp_get_speaker_list(rtsp_conn_info *conn, dacp_spkr_stuff *speaker_info,
+int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info,
int max_size_of_array) {
char *server_reply = NULL;
int speaker_index = -1; // will be incremented before use
}
return reply;
}
+
+void dacp_get_volume(void) {
+ // get the speaker volume information from the DACP source and store it in the metadata_hub
+ // A volume command has been sent from the client
+ // let's get the master volume from the DACP remote control
+ struct dacp_speaker_stuff speaker_info[50];
+ // we need the overall volume and the speakers information to get this device's relative volume to
+ // calculate the real volume
+
+ int32_t overall_volume = dacp_get_client_volume();
+ debug(1,"DACP Volume: %d.",overall_volume);
+ int speaker_count = dacp_get_speaker_list((dacp_spkr_stuff *)&speaker_info, 50);
+ // debug(1,"DACP Speaker Count: %d.",speaker_count);
+
+ // get our machine number
+ uint16_t *hn = (uint16_t *)config.hw_addr;
+ uint32_t *ln = (uint32_t *)(config.hw_addr + 2);
+ uint64_t t1 = ntohs(*hn);
+ uint64_t t2 = ntohl(*ln);
+ int64_t machine_number = (t1 << 32) + t2; // this form is useful
+
+ // Let's find our own speaker in the array and pick up its relative volume
+ int i;
+ int32_t relative_volume = 0;
+ for (i = 0; i < speaker_count; i++) {
+ if (speaker_info[i].speaker_number == machine_number) {
+ // debug(1,"Our speaker number found: %ld.",machine_number);
+ relative_volume = speaker_info[i].volume;
+ }
+ }
+ int32_t actual_volume = (overall_volume * relative_volume + 50) / 100;
+ // debug(1,"Overall volume: %d, relative volume: %d%, actual volume:
+ // %d.",overall_volume,relative_volume,actual_volume);
+ // debug(1,"Our actual speaker volume is %d.",actual_volume);
+ if (metadata_store.speaker_volume != actual_volume) {
+ metadata_store.speaker_volume = actual_volume;
+ run_metadata_watchers();
+ }
+}
+
char **p,
int32_t *length); // return the code of the next TLV entity and advance the pointer beyond it.
-int32_t dacp_get_client_volume(rtsp_conn_info *conn); // return the overall volume from the client
-int dacp_set_include_speaker_volume(rtsp_conn_info *conn, int64_t machine_number, int32_t vo);
-int dacp_set_speaker_volume(rtsp_conn_info *conn, int64_t machine_number, int32_t vo);
-int dacp_get_speaker_list(rtsp_conn_info *conn, dacp_spkr_stuff *speaker_array,
+int dacp_set_speaker_volume(int64_t machine_number, int32_t vo);
+
+int dacp_get_speaker_list(dacp_spkr_stuff *speaker_array,
int max_size_of_array);
void set_dacp_server_information(rtsp_conn_info *conn); // tell the DACP conversation thread that
// the dacp server information has been set
// or changed
int send_simple_dacp_command(const char *command);
+
+void dacp_get_volume(void); // get the speaker volume information from the DACP source and store it in the metadata_hub
enum play_status_type player_state; // this is the state of the actual player itself, which can be a bit noisy.
+ int speaker_volume; // this is the actual speaker volume, allowing for the main volume and the speaker volume control
+ int previous_speaker_volume; // this is needed to prevent a loop
metadata_watcher watchers[number_of_watchers]; // functions to call if the metadata is changed.
void *watchers_data[number_of_watchers]; // their individual data
* All rights reserved.
*
* Modifications for audio synchronisation
- * and related work, copyright (c) Mike Brady 2014
+ * and related work, copyright (c) Mike Brady 2014 -- 2018
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
#include "dbus-service.h"
#endif
-#ifdef HAVE_MPRIS
-#include "mpris-interface.h"
-#include "mpris-player-interface.h"
-#include "mpris-service.h"
-#endif
-
#include "common.h"
#include "player.h"
#include "rtp.h"
// say we have started playing here
#ifdef HAVE_METADATA_HUB
- if ((conn->play_state != SST_stopped) && (conn->play_state != SST_playing)) {
- conn->play_state = SST_playing;
- debug(1, "Player State: Playing");
- metadata_store.player_state = PS_PLAYING;
-// media_player2_player_set_playback_status(mprisPlayerPlayerSkeleton, "Playing");
- }
+ if (metadata_store.player_state != PS_PLAYING) {
+ metadata_store.player_state = PS_PLAYING;
+ run_metadata_watchers();
+ }
#endif
if (reference_timestamp) { // if we have a reference time
// debug(1,"First frame seen with timestamp...");
void player_volume(double airplay_volume, rtsp_conn_info *conn) {
command_set_volume(airplay_volume);
-
-#ifdef HAVE_DBUS
- // A volume command has been sent from the client
- // let's get the master volume from the DACP remote control
-
- struct dacp_speaker_stuff speaker_info[50];
- // we need the overall volume and the speakers information to get this device's relative volume to
- // calculate the real volume
-
- int32_t overall_volume = dacp_get_client_volume(conn);
- // debug(1,"DACP Volume: %d.",overall_volume);
- int speaker_count = dacp_get_speaker_list(conn, (dacp_spkr_stuff *)&speaker_info, 50);
- // debug(1,"DACP Speaker Count: %d.",speaker_count);
-
- // get our machine number
- uint16_t *hn = (uint16_t *)config.hw_addr;
- uint32_t *ln = (uint32_t *)(config.hw_addr + 2);
- uint64_t t1 = ntohs(*hn);
- uint64_t t2 = ntohl(*ln);
- int64_t machine_number = (t1 << 32) + t2; // this form is useful
-
- // Let's find our own speaker in the array and pick up its relative volume
- int i;
- int32_t relative_volume = 0;
- for (i = 0; i < speaker_count; i++) {
- if (speaker_info[i].speaker_number == machine_number) {
- // debug(1,"Our speaker number found: %ld.",machine_number);
- relative_volume = speaker_info[i].volume;
- }
- }
- int32_t actual_volume = (overall_volume * relative_volume + 50) / 100;
- // debug(1,"Overall volume: %d, relative volume: %d%, actual volume:
- // %d.",overall_volume,relative_volume,actual_volume);
- // debug(1,"Our actual speaker volume is %d.",actual_volume);
- conn->dacp_volume = actual_volume; // this is needed to prevent a loop
- shairport_sync_set_volume(SHAIRPORT_SYNC(shairportSyncSkeleton), actual_volume);
+#ifdef HAVE_DACP_CLIENT
+ dacp_get_volume();
#endif
+
player_volume_without_notification(airplay_volume, conn);
}
#ifdef CONFIG_METADATA
send_ssnc_metadata('pfls', NULL, 0, 1);
#endif
-#if defined(HAVE_MPRIS)
- if ((conn->play_state != SST_stopped) && (conn->play_state != SST_paused))
- conn->play_state = SST_paused;
- debug(1, "MPRIS Paused");
- media_player2_player_set_playback_status(mprisPlayerPlayerSkeleton, "Paused");
+
+#ifdef HAVE_METADATA_HUB
+ if (metadata_store.player_state != PS_PAUSED) {
+ metadata_store.player_state = PS_PAUSED;
+ run_metadata_watchers();
+ }
#endif
+
}
int player_play(rtsp_conn_info *conn) {
debug(1, "Error setting stack size for player_thread: %s", strerror(errno));
pthread_create(pt, &tattr, player_thread_func, (void *)conn);
pthread_attr_destroy(&tattr);
-#if defined(HAVE_MPRIS)
- if (conn->play_state != SST_playing)
- conn->play_state = SST_playing;
- debug(1, "MPRIS Playing (play)");
- media_player2_player_set_playback_status(mprisPlayerPlayerSkeleton, "Playing");
+#ifdef HAVE_METADATA_HUB
+ if (metadata_store.player_state != PS_PLAYING) {
+ metadata_store.player_state = PS_PLAYING;
+ run_metadata_watchers();
+ }
#endif
return 0;
}
command_stop();
free(conn->player_thread);
conn->player_thread = NULL;
-#if defined(HAVE_MPRIS)
- if (conn->play_state != SST_stopped)
- conn->play_state = SST_stopped;
- debug(1, "MPRIS Stopped");
- media_player2_player_set_playback_status(mprisPlayerPlayerSkeleton, "Stopped");
+#ifdef HAVE_METADATA_HUB
+ if (metadata_store.player_state != PS_STOPPED) {
+ metadata_store.player_state = PS_STOPPED;
+ run_metadata_watchers();
+ }
#endif
-
} else {
debug(3, "player thread of RTSP conversation %d is already deleted.", conn->connection_number);
}
#define time_ping_history 8
-#if defined(HAVE_DBUS) || defined(HAVE_MPRIS)
-enum session_status_type {
- SST_stopped = 0, // not playing anything
- SST_paused, // paused
- SST_playing,
-} sst_type;
-#endif
-
typedef struct time_ping_record {
uint64_t local_to_remote_difference;
uint64_t dispersion;
int64_t minimum_latency; // set if an a=min-latency: line appears in the ANNOUNCE message; zero otherwise
int64_t maximum_latency; // set if an a=max-latency: line appears in the ANNOUNCE message; zero otherwise
-#if defined(HAVE_DBUS) || defined(HAVE_MPRIS)
- enum session_status_type play_state;
-#endif
int fd;
int authorized; // set if a password is required and has been supplied
stream_cfg stream;