ympd/src/mpd_client.c

263 lines
6.2 KiB
C
Raw Normal View History

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-05 23:15:24 +00:00
unsigned queue_version;
2013-11-04 17:18:38 +00:00
int callback_ympd(struct libwebsocket_context *context,
2013-11-04 17:18:38 +00:00
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
void *user, void *in, size_t len)
{
size_t n;
int 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;
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
lwsl_info("mpd_client: "
2013-11-04 23:17:28 +00:00
"LWS_CALLBACK_ESTABLISHED\n");
break;
2013-11-04 17:18:38 +00:00
case LWS_CALLBACK_SERVER_WRITEABLE:
buf = (char *)malloc(MAX_SIZE + LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING);
if(buf == NULL) {
lwsl_err("ERROR Failed allocating memory\n");
return -1;
}
p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
if(mpd_conn_state != MPD_CONNECTED) {
n = snprintf(p, MAX_SIZE, "{\"type\":\"disconnected\"}");
}
2013-11-05 23:15:24 +00:00
else if(pss->queue_version != queue_version) {
n = mpd_put_playlist(p);
pss->queue_version = queue_version;
}
else if(pss->do_send & DO_SEND_STATE) {
2013-11-04 23:17:28 +00:00
n = mpd_put_state(p);
pss->do_send &= ~DO_SEND_STATE;
}
else if(pss->do_send & DO_SEND_PLAYLIST) {
2013-11-04 23:17:28 +00:00
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 {
2013-11-04 23:17:28 +00:00
n = mpd_put_state(p);
}
if(n > 0)
m = libwebsocket_write(wsi, (unsigned char*)p, n, LWS_WRITE_TEXT);
2013-11-04 23:17:28 +00:00
if (m < n) {
lwsl_err("ERROR %d writing to socket\n", n, m);
free(buf);
2013-11-04 23:17:28 +00:00
return -1;
}
free(buf);
2013-11-04 23:17:28 +00:00
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_GET_TRACK_INFO))
pss->do_send |= DO_SEND_TRACK_INFO;
else if(!strcmp((const char *)in, MPD_API_UPDATE_DB)) {
mpd_send_update(conn, NULL);
mpd_response_finish(conn);
}
else if(!strcmp((const char *)in, MPD_API_SET_PAUSE)) {
2013-11-04 23:17:28 +00:00
mpd_send_toggle_pause(conn);
mpd_response_finish(conn);
}
else if(!strcmp((const char *)in, MPD_API_SET_PREV)) {
2013-11-04 23:17:28 +00:00
mpd_send_previous(conn);
mpd_response_finish(conn);
}
else if(!strcmp((const char *)in, MPD_API_SET_NEXT)) {
2013-11-04 23:17:28 +00:00
mpd_send_next(conn);
mpd_response_finish(conn);
}
else if(!strncmp((const char *)in, MPD_API_SET_VOLUME, sizeof(MPD_API_SET_VOLUME)-1)) {
2013-11-04 23:17:28 +00:00
unsigned int volume;
if(sscanf(in, "MPD_API_SET_VOLUME,%ud", &volume) && volume < 100)
mpd_run_set_volume(conn, volume);
}
break;
2013-11-04 23:17:28 +00:00
default:
break;
2013-11-04 17:18:38 +00:00
}
return 0;
}
void mpd_loop()
{
switch (mpd_conn_state) {
case MPD_DISCONNECTED:
/* Try to connect */
conn = mpd_connection_new("127.0.0.1", 6600, 3000);
if (conn == NULL) {
lwsl_err("Out of memory.");
mpd_conn_state = MPD_FAILURE;
return;
}
2013-11-04 17:18:38 +00:00
if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {
lwsl_notice("MPD connection: %s\n", mpd_connection_get_error_message(conn));
mpd_conn_state = MPD_FAILURE;
return;
}
2013-11-04 17:18:38 +00:00
lwsl_notice("MPD connected.\n");
mpd_conn_state = MPD_CONNECTED;
break;
2013-11-04 17:18:38 +00:00
case MPD_FAILURE:
lwsl_notice("MPD connection failed.\n");
if(conn != NULL)
mpd_connection_free(conn);
conn = NULL;
mpd_conn_state = MPD_DISCONNECTED;
break;
2013-11-04 17:18:38 +00:00
case MPD_CONNECTED:
/* Nothing to do */
break;
2013-11-04 17:18:38 +00:00
}
}
2013-11-05 23:15:24 +00:00
char* mpd_get_title(struct mpd_song const *song)
2013-11-04 23:17:28 +00:00
{
2013-11-05 23:15:24 +00:00
char *str, *ptr;
str = (char *)mpd_song_get_tag(song, MPD_TAG_TITLE, 0);
if(str == NULL)
str = (char *)mpd_song_get_uri(song);
if(str == NULL)
return NULL;
2013-11-05 23:15:24 +00:00
ptr = str;
2013-11-04 23:17:28 +00:00
while(*ptr++ != '\0')
if(*ptr=='"')
*ptr=' ';
2013-11-05 23:15:24 +00:00
2013-11-04 23:17:28 +00:00
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_err("MPD status: %s\n", mpd_connection_get_error_message(conn));
2013-11-04 17:18:38 +00:00
mpd_conn_state = MPD_FAILURE;
return 0;
2013-11-04 17:18:38 +00:00
}
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-05 23:15:24 +00:00
queue_version = mpd_status_get_queue_version(status);
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
return len;
2013-11-04 17:18:38 +00:00
}
int mpd_put_current_song(char* buffer)
{
struct mpd_song *song;
int len;
2013-11-04 17:18:38 +00:00
song = mpd_run_current_song(conn);
if (song != NULL) {
len = snprintf(buffer, MAX_SIZE, "{\"type\": \"current_song\", \"data\": {"
2013-11-05 23:15:24 +00:00
"{\"id\":%d, \"duration\":%d, \"title\":\"%s\"},",
mpd_song_get_id(song),
mpd_song_get_duration(song),
2013-11-05 23:15:24 +00:00
mpd_get_title(song)
2013-11-04 17:18:38 +00:00
);
mpd_song_free(song);
}
mpd_response_finish(conn);
return len;
2013-11-04 17:18:38 +00:00
}
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,
2013-11-05 23:15:24 +00:00
"{\"id\":%d, \"pos\":%d, \"duration\":%d, \"title\":\"%s\"},",
2013-11-04 23:17:28 +00:00
mpd_song_get_id(song),
2013-11-05 23:15:24 +00:00
mpd_song_get_pos(song),
2013-11-04 23:17:28 +00:00
mpd_song_get_duration(song),
2013-11-05 23:15:24 +00:00
mpd_get_title(song)
2013-11-04 23:17:28 +00:00
);
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
/* remove last ',' */
cur--;
cur += snprintf(cur, end - cur, "] }");
printf("buffer: %s\n", buffer);
return cur - buffer;
}