2013-11-04 17:18:38 +00:00
|
|
|
|
|
|
|
#include <mpd/client.h>
|
|
|
|
#include <mpd/status.h>
|
|
|
|
#include <mpd/song.h>
|
|
|
|
#include <mpd/entity.h>
|
|
|
|
#include <mpd/search.h>
|
|
|
|
#include <mpd/tag.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "mpd_client.h"
|
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
#define MAX_SIZE 9000*10
|
|
|
|
|
2013-11-04 17:18:38 +00:00
|
|
|
struct mpd_connection *conn = NULL;
|
|
|
|
enum mpd_conn_states mpd_conn_state = MPD_DISCONNECTED;
|
|
|
|
enum mpd_state mpd_play_state = MPD_STATE_UNKNOWN;
|
2013-11-04 23:17:28 +00:00
|
|
|
static int global_send;
|
2013-11-04 17:18:38 +00:00
|
|
|
|
|
|
|
callback_ympd(struct libwebsocket_context *context,
|
|
|
|
struct libwebsocket *wsi,
|
|
|
|
enum libwebsocket_callback_reasons reason,
|
|
|
|
void *user, void *in, size_t len)
|
|
|
|
{
|
|
|
|
int n, m;
|
2013-11-04 23:17:28 +00:00
|
|
|
char *buf = NULL, *p;
|
2013-11-04 17:18:38 +00:00
|
|
|
struct per_session_data__ympd *pss = (struct per_session_data__ympd *)user;
|
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
//if(global_send || (pss != NULL && pss->do_send))
|
|
|
|
//{
|
|
|
|
buf = (char *)malloc(MAX_SIZE + LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING);
|
|
|
|
|
|
|
|
if(buf == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
|
|
|
|
//}
|
2013-11-04 17:18:38 +00:00
|
|
|
|
|
|
|
switch (reason) {
|
|
|
|
case LWS_CALLBACK_ESTABLISHED:
|
2013-11-04 23:17:28 +00:00
|
|
|
lwsl_info("callback_dumb_increment: "
|
|
|
|
"LWS_CALLBACK_ESTABLISHED\n");
|
|
|
|
break;
|
2013-11-04 17:18:38 +00:00
|
|
|
|
|
|
|
case LWS_CALLBACK_SERVER_WRITEABLE:
|
2013-11-04 23:17:28 +00:00
|
|
|
if(pss->do_send & DO_SEND_STATE)
|
|
|
|
{
|
|
|
|
n = mpd_put_state(p);
|
|
|
|
pss->do_send &= ~DO_SEND_STATE;
|
|
|
|
}
|
|
|
|
else if(pss->do_send & DO_SEND_PLAYLIST)
|
|
|
|
{
|
|
|
|
n = mpd_put_playlist(p);
|
|
|
|
pss->do_send &= ~DO_SEND_PLAYLIST;
|
|
|
|
}
|
|
|
|
else if(pss->do_send & DO_SEND_TRACK_INFO)
|
|
|
|
n = mpd_put_current_song(p);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
n = mpd_put_state(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
|
|
|
|
if (m < n) {
|
|
|
|
lwsl_err("ERROR %d writing to socket\n", n);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
2013-11-04 17:18:38 +00:00
|
|
|
|
|
|
|
case LWS_CALLBACK_RECEIVE:
|
2013-11-04 23:17:28 +00:00
|
|
|
printf("Got %s\n", (char *)in);
|
|
|
|
|
|
|
|
if(!strcmp((const char *)in, MPD_API_GET_STATE))
|
|
|
|
pss->do_send |= DO_SEND_STATE;
|
|
|
|
else if(!strcmp((const char *)in, MPD_API_GET_PLAYLIST))
|
|
|
|
pss->do_send |= DO_SEND_PLAYLIST;
|
|
|
|
else if(!strcmp((const char *)in, MPD_API_SET_PAUSE))
|
|
|
|
{
|
|
|
|
mpd_send_toggle_pause(conn);
|
|
|
|
mpd_response_finish(conn);
|
|
|
|
}
|
|
|
|
else if(!strcmp((const char *)in, MPD_API_SET_PREV))
|
|
|
|
{
|
|
|
|
mpd_send_previous(conn);
|
|
|
|
mpd_response_finish(conn);
|
|
|
|
}
|
|
|
|
else if(!strcmp((const char *)in, MPD_API_SET_NEXT))
|
|
|
|
{
|
|
|
|
mpd_send_next(conn);
|
|
|
|
mpd_response_finish(conn);
|
|
|
|
}
|
|
|
|
else if(!strncmp((const char *)in, MPD_API_SET_VOLUME, sizeof(MPD_API_SET_VOLUME)-1))
|
|
|
|
{
|
|
|
|
unsigned int volume;
|
|
|
|
if(sscanf(in, "MPD_API_SET_VOLUME,%ud", &volume) && volume < 100)
|
|
|
|
{
|
|
|
|
printf("Setting volume to %d\n", volume);
|
|
|
|
mpd_run_set_volume(conn, volume);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-04 17:18:38 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
/*
|
|
|
|
* this just demonstrates how to use the protocol filter. If you won't
|
|
|
|
* study and reject connections based on header content, you don't need
|
|
|
|
* to handle this callback
|
|
|
|
*/
|
|
|
|
|
|
|
|
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
|
|
|
|
/* you could return non-zero here and kill the connection */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mpd_loop()
|
|
|
|
{
|
|
|
|
switch (mpd_conn_state) {
|
|
|
|
case MPD_DISCONNECTED:
|
|
|
|
/* Try to connect */
|
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
conn = mpd_connection_new("10.23.44.2", 6600, 3000);
|
2013-11-04 17:18:38 +00:00
|
|
|
if (conn == NULL) {
|
|
|
|
lwsl_err("%s", "Out of memory");
|
|
|
|
mpd_conn_state = MPD_FAILURE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {
|
|
|
|
lwsl_notice("MPD Connection: %s", mpd_connection_get_error_message(conn));
|
|
|
|
mpd_conn_state = MPD_FAILURE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mpd_conn_state = MPD_CONNECTED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MPD_FAILURE:
|
|
|
|
if(conn != NULL)
|
|
|
|
mpd_connection_free(conn);
|
|
|
|
conn = NULL;
|
|
|
|
mpd_conn_state = MPD_DISCONNECTED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MPD_CONNECTED:
|
|
|
|
printf("mpd connected\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
const char* encode_string(const char *str)
|
|
|
|
{
|
|
|
|
char *ptr = (char *)str;
|
|
|
|
while(*ptr++ != '\0')
|
|
|
|
if(*ptr=='"')
|
|
|
|
*ptr=' ';
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2013-11-04 17:18:38 +00:00
|
|
|
int mpd_put_state(char* buffer)
|
|
|
|
{
|
|
|
|
struct mpd_status *status;
|
2013-11-04 23:17:28 +00:00
|
|
|
int len;
|
2013-11-04 17:18:38 +00:00
|
|
|
|
|
|
|
status = mpd_run_status(conn);
|
|
|
|
if (!status) {
|
|
|
|
lwsl_notice("MPD Status: %s", mpd_connection_get_error_message(conn));
|
|
|
|
mpd_conn_state = MPD_FAILURE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
len = snprintf(buffer, MAX_SIZE,
|
|
|
|
"{\"type\":\"state\", \"data\":{"
|
2013-11-04 17:18:38 +00:00
|
|
|
" \"state\":%d, \"volume\":%d, \"repeat\":%d,"
|
|
|
|
" \"single\":%d, \"consume\":%d, \"random\":%d, "
|
2013-11-04 23:17:28 +00:00
|
|
|
" \"songpos\": %d, \"elapsedTime\": %d, \"totalTime\":%d, "
|
|
|
|
" \"currentsongid\": %d"
|
2013-11-04 17:18:38 +00:00
|
|
|
"}}",
|
|
|
|
mpd_status_get_state(status),
|
|
|
|
mpd_status_get_volume(status),
|
|
|
|
mpd_status_get_repeat(status),
|
|
|
|
mpd_status_get_single(status),
|
|
|
|
mpd_status_get_consume(status),
|
|
|
|
mpd_status_get_random(status),
|
|
|
|
mpd_status_get_song_pos(status),
|
|
|
|
mpd_status_get_elapsed_time(status),
|
2013-11-04 23:17:28 +00:00
|
|
|
mpd_status_get_total_time(status),
|
|
|
|
mpd_status_get_song_id(status));
|
2013-11-04 17:18:38 +00:00
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
printf("buffer: %s\n", buffer);
|
2013-11-04 17:18:38 +00:00
|
|
|
mpd_status_free(status);
|
2013-11-04 23:17:28 +00:00
|
|
|
//printf("status: %d\n", mpd_response_finish(conn));
|
|
|
|
return len;
|
2013-11-04 17:18:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int mpd_put_current_song(char* buffer)
|
|
|
|
{
|
|
|
|
struct mpd_song *song;
|
|
|
|
|
|
|
|
song = mpd_run_current_song(conn);
|
|
|
|
if (song != NULL) {
|
|
|
|
sprintf(buffer,
|
|
|
|
"{\"type\": \"current_song\", \"data\": {"
|
|
|
|
" \"uri\":%s"
|
|
|
|
"}}",
|
|
|
|
mpd_song_get_uri(song)
|
|
|
|
);
|
|
|
|
mpd_song_free(song);
|
|
|
|
}
|
|
|
|
mpd_response_finish(conn);
|
|
|
|
}
|
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
int mpd_put_playlist(char* buffer)
|
2013-11-04 17:18:38 +00:00
|
|
|
{
|
2013-11-04 23:17:28 +00:00
|
|
|
char *cur = buffer;
|
|
|
|
const char *end = buffer + MAX_SIZE;
|
|
|
|
struct mpd_entity *entity;
|
|
|
|
struct mpd_song const *song;
|
2013-11-04 17:18:38 +00:00
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
mpd_send_list_queue_meta(conn);
|
|
|
|
|
|
|
|
cur += snprintf(cur, end - cur, "{\"type\": \"playlist\", \"data\": [ ");
|
2013-11-04 17:18:38 +00:00
|
|
|
|
|
|
|
for(entity = mpd_recv_entity(conn); entity; entity = mpd_recv_entity(conn)) {
|
|
|
|
|
|
|
|
if(mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
|
2013-11-04 23:17:28 +00:00
|
|
|
song = mpd_entity_get_song(entity);
|
|
|
|
cur += snprintf(cur, end - cur,
|
|
|
|
"{\"id\":%d, \"uri\":\"%s\", \"duration\":%d, \"title\":\"%s\"},",
|
|
|
|
mpd_song_get_id(song),
|
|
|
|
mpd_song_get_uri(song),
|
|
|
|
mpd_song_get_duration(song),
|
|
|
|
encode_string(mpd_song_get_tag(song, MPD_TAG_TITLE, 0))
|
|
|
|
);
|
2013-11-04 17:18:38 +00:00
|
|
|
}
|
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
mpd_entity_free(entity);
|
2013-11-04 17:18:38 +00:00
|
|
|
}
|
2013-11-04 23:17:28 +00:00
|
|
|
//printf("status: %d\n", mpd_response_finish(conn));
|
2013-11-04 17:18:38 +00:00
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
/* remove last ',' */
|
|
|
|
cur--;
|
|
|
|
cur += snprintf(cur, end - cur, "] }");
|
|
|
|
printf("buffer: %s\n", buffer);
|
|
|
|
return cur - buffer;
|
2013-11-04 17:18:38 +00:00
|
|
|
}
|