diff options
| -rw-r--r-- | moc_library.c | 541 | ||||
| -rw-r--r-- | moc_library.h | 47 | ||||
| -rw-r--r-- | moc_x11.c | 142 | 
3 files changed, 730 insertions, 0 deletions
| diff --git a/moc_library.c b/moc_library.c new file mode 100644 index 0000000..1e382aa --- /dev/null +++ b/moc_library.c @@ -0,0 +1,541 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h>  //Header file for sleep(). man 3 sleep for details. +#include <errno.h> +  +#include <pthread.h> +#include <sys/socket.h> +#include <sys/un.h> + +// A normal C function that is executed as a thread +// when its name is specified in pthread_create() +// + +char *moc_socket_path = "/home/calvin/.moc/socket2"; + +/* State of the server. */ +#define STATE_PLAY	0x01 +#define STATE_STOP	0x02 +#define STATE_PAUSE	0x03 +#define CMD_GET_STATE	0x13 /* get the state */ +#define CMD_GET_CTIME	0x0d /* get the current song time */ +#define CMD_GET_TAGS	0x2c /* get tags for the currently played file */ +#define CMD_GET_FILE_TAGS	0x2f	/* get tags for the specified file */ +#define CMD_GET_SNAME	0x0f /* get the stream file name */ +#define MAX_SEND_STRING	4096 +#define RANGE(min, val, max) ((val) >= (min) && (val) <= (max)) + + +/* Definition of events sent by server to the client. */ +#define EV_STATE	0x01 /* server has changed the state */ +#define EV_CTIME	0x02 /* current time of the song has changed */ +#define EV_SRV_ERROR	0x04 /* an error occurred */ +#define EV_BUSY		0x05 /* another client is connected to the server */ +#define EV_DATA		0x06 /* data in response to a request will arrive */ +#define EV_BITRATE	0x07 /* the bitrate has changed */ +#define EV_RATE		0x08 /* the rate has changed */ +#define EV_CHANNELS	0x09 /* the number of channels has changed */ +#define EV_EXIT		0x0a /* the server is about to exit */ +#define EV_PONG		0x0b /* response for CMD_PING */ +#define EV_OPTIONS	0x0c /* the options has changed */ +#define EV_SEND_PLIST	0x0d /* request for sending the playlist */ +#define EV_TAGS		0x0e /* tags for the current file have changed */ +#define EV_STATUS_MSG	0x0f /* followed by a status message */ +#define EV_MIXER_CHANGE	0x10 /* the mixer channel was changed */ +#define EV_FILE_TAGS	0x11 /* tags in a response for tags request */ +#define EV_AVG_BITRATE  0x12 /* average bitrate has changed (new song) */ +#define EV_AUDIO_START	0x13 /* playing of audio has started */ +#define EV_AUDIO_STOP	0x14 /* playing of audio has stopped */ + +/* Events caused by a client that wants to modify the playlist (see + * CMD_CLI_PLIST* commands). */ +#define EV_PLIST_ADD	0x50 /* add an item, followed by the file name */ +#define EV_PLIST_DEL	0x51 /* delete an item, followed by the file name */ +#define EV_PLIST_MOVE	0x52 /* move an item, followed by 2 file names */ +#define EV_PLIST_CLEAR	0x53 /* clear the playlist */ + +/* These events, though similar to the four previous are caused by server + * which takes care of clients' queue synchronization. */ +#define EV_QUEUE_ADD	0x54 +#define EV_QUEUE_DEL	0x55 +#define EV_QUEUE_MOVE	0x56 +#define EV_QUEUE_CLEAR	0x57 +/* Flags for the info decoder function. */ +enum tags_select +{ +  TAGS_COMMENTS	= 0x01, /* artist, title, etc. */ +  TAGS_TIME	= 0x02 /* time of the file. */ +}; + +enum moc_state { +  STOPPED, +  PLAYING, +  PAUSED +}; + +enum moc_status { +  INITIALIZING, +  CONNECTED, +  FAILED_TO_CONNECT, +  ERROR +}; + +struct moc {  +  pthread_mutex_t lock; +  enum moc_status status; +  enum moc_state state; + +  char *filename; +  char *title; +  char *album; +  char *artist; +  int track; +  int time; +  int filled; +}; + +extern const char * moc_str_state(enum moc_state s) { +    static const char *strings[] = { "STOPPED", "PLAYING", "PAUSED"}; +    return strings[s]; + +} + +static char *get_curr_file(int sock); +static char *get_data_str(int sock); +static void *get_event_data (const int sock, const int type); +int send_str (int sock, const char *str); +char *get_str (int sock); +int send_int (int sock, int i); +int get_int (int sock, int *i); + +static char *get_curr_file (const int sock) { +  send_int (sock, CMD_GET_SNAME); +  int ev; +  while(ev != EV_DATA) { +    get_int(sock, &ev); +    fprintf(stderr, "EVENT: 0x%02x\n", ev); +  } +    return get_str(sock); +} +static void wait_for_data (const int sock) { +  int event = -1; +  do { +    fprintf(stderr, "waiting for data last was %d\n", event); +    event = get_int(sock, &event); +    if (event == EV_EXIT) { +      fprintf(stderr, "The server exited!"); +      pthread_exit(NULL); +    } +    if(event == EV_STATE) { +      char *skip; +      skip = get_str(sock); +      fprintf(stderr, "got str%s\n", skip); +    } +    if (event != EV_DATA) +      get_event_data(sock, event); +  } while (event != EV_DATA); +} + +static void *get_event_data (const int sock, const int type) +{ +  switch (type) { +    case EV_PLIST_ADD: +    case EV_QUEUE_ADD: +      break; +      // return recv_item_from_srv (); +    case EV_PLIST_DEL: +    case EV_QUEUE_DEL: +    case EV_STATUS_MSG: +    case EV_SRV_ERROR: +      return get_str(sock); +    case EV_FILE_TAGS: +      //	return recv_tags_data_from_srv (); +      break; +    case EV_PLIST_MOVE: +      break; +  } + +  return NULL; +} +static char *get_data_str(int sock) { +  wait_for_data (sock); +  return get_str(sock); +} + + +int send_str (int sock, const char *str) +{ +  int len; + +  len = strlen (str); +  if (!send_int (sock, len)) +    return 0; + +  if (send (sock, str, len, 0) != len) +    return 0; + +  return 1; +} +char *get_str (int sock) { +  int len; +  int res, nread = 0; +  char *str; + +  if (!get_int(sock, &len)) +    return NULL; + +  if (!RANGE(0, len, MAX_SEND_STRING)) { +    printf("Bad string length."); +    return NULL; +  } + +  str = (char *)malloc (sizeof(char) * (len + 1)); +  while (nread < len) { +    res = recv (sock, str + nread, len - nread, 0); +    if (res == -1) { +      printf("recv() failed when getting string: %s\n", +          strerror(errno)); +      free (str); +      return NULL; +    } +    if (res == 0) { +      printf("Unexpected EOF when getting string\n"); +      free (str); +      return NULL; +    } +    nread += res; +  } +  str[len] = 0; + +  return str; +} +int send_int (int sock, int i) +{ +  int res; + +  res = send (sock, &i, sizeof(int), 0); +  if (res == -1) +    printf("send() failed: %s", strerror(errno)); + +  return res == sizeof(int) ? 1 : 0; +} + +int get_int (int sock, int *i) +{ +  int res; + +  res = recv (sock, i, sizeof(int), 0); +  if (res == -1) +    printf("recv() failed when getting int: %s", strerror(errno)); + +  return res == sizeof(int) ? 1 : 0; +} + +static int moc_server_connect () +{ +  char *path = moc_socket_path; +  struct sockaddr_un sock_name; +  int sock; + +  /* Create a socket */ +  if ((sock = socket (PF_LOCAL, SOCK_STREAM, 0)) == -1) +    return -1; + +  sock_name.sun_family = AF_LOCAL; +  strcpy (sock_name.sun_path, moc_socket_path); + +  if (connect(sock, (struct sockaddr *)&sock_name, +        SUN_LEN(&sock_name)) == -1) { +    close (sock); +    fprintf(stderr, "%s at (%s)\n", strerror(errno), sock_name); +    return -1; +  } + +  return sock; +} + + +void update_state(struct moc *data, int state) { +    fprintf(stderr, "moc: state %d, state\n"); +    if(state == STATE_PLAY) { +        data->state = PLAYING; +        fprintf(stderr, "moc: playing\n"); +    } +    if(state == STATE_PAUSE) { +        data->state = PAUSED; +        fprintf(stderr, "moc: paused\n"); +    } +    if(state == STATE_STOP) { +        data->state = STOPPED; +        fprintf(stderr, "moc: state stopped\n"); +    } +} +void *moc_loop(void *input) { + + +  struct moc *data = (struct moc*)input; + +  int srv_sock = -1; + +  srv_sock = moc_server_connect(); +  if(srv_sock == -1) {  +    pthread_mutex_lock(&data->lock); +    data->status = FAILED_TO_CONNECT; +    pthread_mutex_unlock(&data->lock); +    pthread_exit(NULL); +  } + +  data->status = CONNECTED; + +  int last_cmd = -1; +  int event = -1; + +  send_int(srv_sock, CMD_GET_STATE); +  last_cmd = EV_STATE; +  while(get_int(srv_sock, &event)) { +    switch (event) { +      // handle our data. we MUST know what the last request was otherwise we +      // don't know how to parse it. +      case EV_DATA: +        fprintf(stderr, "moc: EV_DATA\n"); +        if(last_cmd == EV_CTIME) { +          get_int(srv_sock, &data->time); +          fprintf(stderr, "moc: update ctime\n"); +        } +        //  on state change, we need to figure out what file we have and what +        //  tags it has. +        else if(last_cmd == EV_STATE) { +          int state; +          get_int(srv_sock, &state); +          update_state(data, state); + +          char *file = get_curr_file(srv_sock); +          fprintf(stderr, "moc: current file %s\n", file); +          // if it's the same file as we had, don't update. +          if(data->filename == NULL || strcmp(file, data->filename) != 0) { +            fprintf(stderr, "moc: new file, asking for tags\n"); +            data->filename = file; +            // get tags. +            send_int(srv_sock, CMD_GET_FILE_TAGS); +            send_str(srv_sock, file); +            send_int(srv_sock,TAGS_COMMENTS | TAGS_TIME); +            last_cmd = EV_FILE_TAGS; +          } +        } +        else { +          fprintf(stderr, "moc: shit i have data IDK what it is\n"); +        } +        last_cmd = -1; + +        break; +      case EV_BUSY: +        fprintf(stderr, "moc: EV_BUSY\n"); +        break; +      case EV_CTIME: +        fprintf(stderr, "moc: EV_CTIME\n"); +        last_cmd = EV_CTIME; +        send_int(srv_sock, CMD_GET_CTIME); +        break; +      case EV_STATE: +        fprintf(stderr, "moc: EV_STATE\n"); +        last_cmd = EV_STATE; +        send_int(srv_sock, CMD_GET_STATE); +        break; +      case EV_EXIT: +        fprintf(stderr,"moc: EV_EXIT\n"); +        break; +      case EV_BITRATE: +        fprintf(stderr, "moc: EV_BITRATE\n"); +        break; +      case EV_RATE: +        fprintf(stderr, "moc: EV_RATE\n"); +        break; +      case EV_CHANNELS: +        printf("moc: EV_CHANNELS\n"); +        break; +      case EV_SRV_ERROR: +        printf("moc: EV_SRV_ERROR\n"); +        break; +      case EV_OPTIONS: +        printf("moc: EV_OPTIONS\n"); +        break; +      case EV_SEND_PLIST: +      case EV_PLIST_ADD: +      case EV_PLIST_CLEAR: +      case EV_PLIST_DEL: +      case EV_PLIST_MOVE: +        printf("moc: EV_PLAYLIST\n"); +      case EV_TAGS: +        last_cmd = EV_TAGS; +        printf("moc: EV_TAGS\n"); +        break; +      case EV_STATUS_MSG: +        printf("moc: EV_STATUS_MSG\n"); +        printf("moc: status update: %s\n", get_str(srv_sock)); +        break; +      case EV_MIXER_CHANGE: +        printf("moc: EV_MIXER_CHANGE\n"); +        break; +      case EV_FILE_TAGS: +        printf("moc: EV_FILE_TAGS\n"); + +        if (!(data->filename = get_str(srv_sock))) { +          fprintf(stderr, "Error while receiving filename\n"); +        } + +        if (!(data->title = get_str(srv_sock))) { +          fprintf(stderr, "Error while receiving title\n"); +        } + +        if (!(data->artist = get_str(srv_sock))) { +          fprintf(stderr, "Error while receiving artist\n"); +        } + +        if (!(data->album = get_str(srv_sock))) { +          fprintf(stderr, "Error while receiving album\n"); +        } + +        if (!get_int(srv_sock, &data->track)) { +          fprintf(stderr, "Error while receiving track\n"); +        } + +        if (!get_int(srv_sock, &data->time)) { +          fprintf(stderr, "Error while receiving time\n"); +        } + +        if (!get_int(srv_sock, &data->filled)) { +          fprintf(stderr, "Error while receiving filled\n"); +        } + +        break; +      case EV_AVG_BITRATE: +        printf("moc: EV_AVG_BITRATE\n"); +        break; +      case EV_AUDIO_START: +        printf("moc: AUDIO START\n"); +        break; +      case EV_AUDIO_STOP: +        printf("moc: AUDIO STOP\n"); +        break; +      default: +        fprintf(stderr, "Unknown event: 0x%02x!\n", event); +        break; +    } +  } +} +void *moc_loop2(void *input) { + +  struct moc *data = (struct moc*)input; + +  int srv_sock = -1; + +  srv_sock = moc_server_connect(); +  if(srv_sock == -1) {  +    pthread_mutex_lock(&data->lock); +    data->status = FAILED_TO_CONNECT; +    pthread_mutex_unlock(&data->lock); +    pthread_exit(NULL); +  } +  data->status = CONNECTED; + +  while(1) { + +    int state = 0; +    int ev = 0; + +    while(ev != EV_DATA) { +      send_int(srv_sock, CMD_GET_STATE); +      if (!get_int(srv_sock, &ev)) { +        fprintf(stderr, "Can't get data from the server.\n"); +      } +      fprintf(stderr, "EVENT: 0x%02x\n", ev); +    } + +    if(!get_int(srv_sock, &state)) { +      fprintf(stderr, "Can't get state from the server!\n"); +    } +    fprintf(stderr, "Got state%d\n", state); + +    pthread_mutex_lock(&data->lock); +    if(state == STATE_PLAY) { +        data->state = PLAYING; +        fprintf(stderr, "moc: playing\n"); +    } +    if(state == STATE_PAUSE) { +        data->state = PAUSED; +        fprintf(stderr, "moc: paused\n"); +    } +    if(state == STATE_STOP) { +        data->state = STOPPED; +        fprintf(stderr, "moc: stopped\n"); +    } +    pthread_mutex_unlock(&data->lock); +    continue; + +    char *file = get_curr_file(srv_sock); +    fprintf(stderr, "moc: filename: %s\n", file); + +    send_int(srv_sock, CMD_GET_FILE_TAGS); +    send_str(srv_sock, file); +    send_int(srv_sock,TAGS_COMMENTS | TAGS_TIME); + +    // filename first. +    if (!(data->filename = get_str(srv_sock))) { +      fprintf(stderr, "Error while receiving filename\n"); +    } + +    if (!(data->title = get_str(srv_sock))) { +      fprintf(stderr, "Error while receiving title\n"); +    } + +    if (!(data->artist = get_str(srv_sock))) { +      fprintf(stderr, "Error while receiving artist\n"); +    } + +    if (!(data->album = get_str(srv_sock))) { +      fprintf(stderr, "Error while receiving album\n"); +    } + +    if (!get_int(srv_sock, &data->track)) { +      fprintf(stderr, "Error while receiving track\n"); +    } + +    if (!get_int(srv_sock, &data->time)) { +      fprintf(stderr, "Error while receiving time\n"); +    } + +    if (!get_int(srv_sock, &data->filled)) { +      fprintf(stderr, "Error while receiving filled\n"); +    } + + + +    fprintf(stderr, "moc: end switch\n"); + +    pthread_mutex_unlock(&data->lock); +    fprintf(stderr, "end lock\n"); +  } + +    fprintf(stderr, "moc: end of loop\n"); +    return NULL; +} +   +extern struct moc *moc_init() { + +  struct moc *moc = (struct moc*)malloc(sizeof(struct moc)); +  moc->filename = NULL; +  moc->title = NULL; +  moc->album = NULL; +  moc->artist = NULL; +  moc->time = -1; +  pthread_t thread_id; + +  if (pthread_mutex_init(&moc->lock, NULL) != 0) { +    printf("\n mutex init has failed\n"); +    return NULL; +  } +  moc->status = INITIALIZING; + +  pthread_create(&thread_id, NULL, moc_loop, (void *)moc); +  return moc; +} diff --git a/moc_library.h b/moc_library.h new file mode 100644 index 0000000..60a9c09 --- /dev/null +++ b/moc_library.h @@ -0,0 +1,47 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h>  //Header file for sleep(). man 3 sleep for details. +#include <errno.h> +  +#include <pthread.h> +#include <sys/socket.h> +#include <sys/un.h> + + +/* Flags for the info decoder function. */ +enum tags_select +{ +  TAGS_COMMENTS	= 0x01, /* artist, title, etc. */ +  TAGS_TIME	= 0x02 /* time of the file. */ +}; + +enum moc_state { +  STOPPED, +  PLAYING, +  PAUSED +}; + +enum moc_status { +  INITIALIZING, +  CONNECTED, +  FAILED_TO_CONNECT, +  ERROR +}; + +struct moc {  +  pthread_mutex_t lock; +  enum moc_status status; +  enum moc_state state; + +  char *filename; +  char *title; +  char *album; +  char *artist; +  int track; +  int time; +  int filled; +}; + +extern const char * moc_str_state(enum moc_state s); +extern struct moc * moc_init(); + diff --git a/moc_x11.c b/moc_x11.c new file mode 100644 index 0000000..efc4ce3 --- /dev/null +++ b/moc_x11.c @@ -0,0 +1,142 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h>  //Header file for sleep(). man 3 sleep for details. +#include <errno.h> +  +#include <pthread.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xos.h> + +#include "moc_library.h" + +void *xmalloc (size_t size) +{ +  void *p; + + +  if ((p = malloc(size)) == NULL) {  +    fprintf(stderr, "Can't allocate memory!"); +    exit(0); +  } +  return p; +} + +/* Obtains the next X11 event with specified timeout. */ +  static int XNextEventTimed(Display* dsp, XEvent* event_return, long millis) { +  if (millis == 0) +  { +    XNextEvent(dsp, event_return); +    return True; +  } + +  struct timeval tv; +  tv.tv_sec = millis / 1000; +  tv.tv_usec = (millis % 1000) * 1000; + +  XFlush(dsp); +  if (XPending(dsp)) +  { +    XNextEvent(dsp, event_return); +    return True; +  } +  else +  { +    int fd = ConnectionNumber(dsp); +    fd_set readset; +    FD_ZERO(&readset); +    FD_SET(fd, &readset); +    if (select(fd+1, &readset, NULL, NULL, &tv) <= 0) +    { +      return False; +    } +    else +    { +      if (XPending(dsp)) +      { +        XNextEvent(dsp, event_return); +        return True; +      } +      else +      { +        return False; +      } +    } +  } +} + +char *time_format(int sec) { + +  int h = (sec/3600); +  int m = (sec -(3600*h))/60; +  int s = (sec -(3600*h)-(m*60)); + +  char *str = xmalloc(256); +  if(h) { +    sprintf(str, "%d:%2d:%02d",h,m,s); +  } else { +    sprintf(str, "%02d:%02d",m,s); +  } +  return str; +} + +int main() { + +    Display* dpy = XOpenDisplay(NULL); +    if (dpy == NULL) +    { +      fprintf(stderr, "Cannot open display\n"); +      exit(1); +    } + +    int s = DefaultScreen(dpy); +    Window win = XCreateSimpleWindow(dpy, RootWindow(dpy, s), 10, 10, 660, 200, 1, +        BlackPixel(dpy, s), WhitePixel(dpy, s)); +    XSelectInput(dpy, win, ExposureMask | ButtonPress | KeyPressMask); +    XMapWindow(dpy, win); + +    XStoreName(dpy, win, "mocicon"); + +    Atom WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False); +    XSetWMProtocols(dpy, win, &WM_DELETE_WINDOW, 1); + +    struct moc *mh = moc_init(); +    if(mh == NULL) { +      return 1; +    } + +    XEvent e; +    while(1) { +      int got_event = XNextEventTimed(dpy, &e, 250); + +      if(mh->status != CONNECTED) { +        printf("can't connect\n"); +      } + +      XClearWindow(dpy, win); +        int y_offset = 20; +        int x = 10; +        pthread_mutex_lock(&mh->lock); +        if(mh->state == PLAYING || mh->state == PAUSED) { +          char *timestr= time_format(mh->time); + +          XDrawString(dpy, win, DefaultGC(dpy, s), x, y_offset, mh->title, strlen(mh->title)); +          y_offset += 15; +          XDrawString(dpy, win, DefaultGC(dpy, s), x, y_offset, mh->artist, strlen(mh->artist)); +          y_offset += 15; +          XDrawString(dpy, win, DefaultGC(dpy, s), x, y_offset, mh->album, strlen(mh->album)); +          y_offset += 15; +          XDrawString(dpy, win, DefaultGC(dpy, s), x, y_offset, timestr, strlen(timestr)); +          y_offset += 15; + + +          free(timestr); + +        } +        pthread_mutex_unlock(&mh->lock); + +      } +    }; | 
