Logo Search packages:      
Sourcecode: ladcca version File versions  Download package

alsa_patch.c

/*
 *   LADCCA
 *    
 *   Copyright (C) 2002 Robert Ham <rah@bash.sh>
 *    
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdlib.h>

#include <alsa/asoundlib.h>

#include <ladcca/internal_headers.h>

#include "client.h"
#include "alsa_patch.h"
#include "alsa_client.h"

void
alsa_patch_init (alsa_patch_t * patch)
{
  int err;
  
  err = snd_seq_port_subscribe_malloc (&patch->sub);
  if (err)
    abort ();
  
  uuid_clear (patch->src_id);
  uuid_clear (patch->dest_id);
}

void
alsa_patch_free (alsa_patch_t * patch)
{
  snd_seq_port_subscribe_free (patch->sub);
}

alsa_patch_t *
alsa_patch_new ()
{
  alsa_patch_t * patch;
  patch = cca_malloc (sizeof (alsa_patch_t));
  alsa_patch_init (patch);
  return patch;
}

alsa_patch_t *
alsa_patch_new_with_sub (const snd_seq_port_subscribe_t * sub)
{
  alsa_patch_t * patch;
  patch = alsa_patch_new ();
  alsa_patch_set_sub (patch, sub);
  return patch;
}

alsa_patch_t *
alsa_patch_new_with_query (const snd_seq_query_subscribe_t * query)
{
  alsa_patch_t * patch;
  patch = alsa_patch_new ();
  alsa_patch_set_sub_from_query (patch, query);
  return patch;
}

void
alsa_patch_destroy (alsa_patch_t * patch)
{
  alsa_patch_free (patch);
  free (patch);
}

const snd_seq_port_subscribe_t *
alsa_patch_get_sub (const alsa_patch_t * patch)
{
  return patch->sub;
}

int
alsa_patch_src_id_is_null (alsa_patch_t * patch)
{
  return uuid_is_null (patch->src_id);
}

int
alsa_patch_to_dest_is_null   (alsa_patch_t * patch)
{
  return uuid_is_null (patch->dest_id);
}

void
alsa_patch_set_sub     (alsa_patch_t * patch, const snd_seq_port_subscribe_t * sub)
{
  if (sub)
    snd_seq_port_subscribe_copy (patch->sub, sub);
}

void
alsa_patch_set_sub_from_query (alsa_patch_t * patch, const snd_seq_query_subscribe_t * query)
{
  if (query)
    alsa_patch_set_sub (patch, query_to_sub (query));
}


static void
alsa_patch_set_client_id (cca_list_t * alsa_mgr_clients, unsigned char alsa_client_id, uuid_t patch_client_id)
{
  alsa_client_t * client;

  for (; alsa_mgr_clients; alsa_mgr_clients = cca_list_next (alsa_mgr_clients))
    {
      client = (alsa_client_t *) alsa_mgr_clients->data;
      
      if (client->client_id == alsa_client_id)
        {
          uuid_copy (patch_client_id, client->id); 
          return;
        }
    }
}

void
alsa_patch_set   (alsa_patch_t * patch, cca_list_t * alsa_mgr_clients)
{
  const snd_seq_addr_t * addr;
  
  addr = snd_seq_port_subscribe_get_sender (patch->sub);
  alsa_patch_set_client_id (alsa_mgr_clients, addr->client, patch->src_id);
  
  addr = snd_seq_port_subscribe_get_dest (patch->sub);
  alsa_patch_set_client_id (alsa_mgr_clients, addr->client, patch->dest_id);
}

typedef const snd_seq_addr_t * (*alsa_patch_get_sub_addr_func) (const snd_seq_port_subscribe_t *info);
typedef void (*alsa_patch_set_sub_addr_func) (snd_seq_port_subscribe_t *info, const snd_seq_addr_t *addr);

int
alsa_patch_unset_client_id (alsa_patch_t * patch,
                      cca_list_t * alsa_mgr_clients,
                      uuid_t patch_client_id,
                      alsa_patch_get_sub_addr_func get_sub_addr,
                      alsa_patch_set_sub_addr_func set_sub_addr)
{
  alsa_client_t * client;

  for (; alsa_mgr_clients; alsa_mgr_clients = cca_list_next (alsa_mgr_clients))
    {
      client = (alsa_client_t *) alsa_mgr_clients->data;

      if (uuid_compare (patch_client_id, client->id) == 0)
      {
        snd_seq_addr_t addr;

#ifdef LADCCA_DEBUG
          {
          char id[37];
          uuid_unparse (client->id, id);
          CCA_DEBUGARGS ("found alsa mgr client with id '%s'", id);
        }
#endif

        addr.client = client->client_id;
        addr.port = get_sub_addr(patch->sub)->port;
        set_sub_addr (patch->sub, &addr);

        return 0;
      }
    }

#ifdef LADCCA_DEBUG
    {
      char id[37];
      uuid_unparse (client->id, id);
      CCA_DEBUGARGS ("could not find alsa mgr client with id '%s'", id);
    }
#endif

  return 1;
}

int
alsa_patch_unset (alsa_patch_t * patch, cca_list_t * alsa_mgr_clients)
{
  int err;
  int not_found = 0;

  if (!uuid_is_null (patch->src_id))
    {
      err = alsa_patch_unset_client_id (patch,
                              alsa_mgr_clients,
                              patch->src_id,
                              snd_seq_port_subscribe_get_sender,
                              snd_seq_port_subscribe_set_sender);
      if (err)
      not_found++;
    }

  if (!uuid_is_null (patch->dest_id))
    {
      err = alsa_patch_unset_client_id (patch,
                              alsa_mgr_clients,
                              patch->dest_id,
                              snd_seq_port_subscribe_get_dest,
                              snd_seq_port_subscribe_set_dest);
      if (err)
      not_found++;
    }

  return not_found;
}

const snd_seq_port_subscribe_t *
query_to_sub (const snd_seq_query_subscribe_t * query)
{
  static snd_seq_port_subscribe_t * sub = NULL;
  
  if (!query)
    return NULL;
  
  if (!sub)
    {
      int err;
      err = snd_seq_port_subscribe_malloc (&sub);
      if (err)
        abort();
    }
  
  snd_seq_port_subscribe_set_sender      (sub, snd_seq_query_subscribe_get_root (query));
  snd_seq_port_subscribe_set_dest        (sub, snd_seq_query_subscribe_get_addr (query));
  snd_seq_port_subscribe_set_exclusive   (sub, snd_seq_query_subscribe_get_exclusive (query));
  snd_seq_port_subscribe_set_time_update (sub, snd_seq_query_subscribe_get_time_update (query));
  snd_seq_port_subscribe_set_time_real   (sub, snd_seq_query_subscribe_get_time_real (query));
  snd_seq_port_subscribe_set_queue       (sub, snd_seq_query_subscribe_get_queue (query));
  
  return sub;
}

void
alsa_patch_switch_clients (alsa_patch_t * patch)
{
  unsigned char from_client, from_port, to_client, to_port;
  snd_seq_addr_t addr;
  const snd_seq_addr_t * addrptr;
  uuid_t id;
                                                                                                                                                       
  addrptr = snd_seq_port_subscribe_get_sender (patch->sub);
  from_client = addrptr->client;
  from_port   = addrptr->port;
                                                                                                                                                       
  addrptr = snd_seq_port_subscribe_get_dest (patch->sub);
  to_client = addrptr->client;
  to_port   = addrptr->port;
                                                                                                                                                       
  addr.client = to_client;
  addr.port   = to_port;
  snd_seq_port_subscribe_set_sender (patch->sub, &addr);
                                                                                                                                                       
  addr.client = from_client;
  addr.port   = from_port;
  snd_seq_port_subscribe_set_dest (patch->sub, &addr);
                                                                                                                                                       
  uuid_copy (id, patch->src_id);
  uuid_copy (patch->src_id, patch->dest_id);
  uuid_copy (patch->dest_id, id);
}


alsa_patch_t *
alsa_patch_dup (const alsa_patch_t * other_patch)
{
  alsa_patch_t * patch;
  
  patch = alsa_patch_new_with_sub (alsa_patch_get_sub (other_patch));

  uuid_copy (patch->src_id, other_patch->src_id);
  uuid_copy (patch->dest_id, other_patch->dest_id);
  
  return patch;
}

unsigned char
alsa_patch_get_src_client    (const alsa_patch_t * patch)
{
  const snd_seq_addr_t * addr;
  
  addr = snd_seq_port_subscribe_get_sender (patch->sub);
  
  return addr->client;
}

unsigned char
alsa_patch_get_src_port      (const alsa_patch_t * patch)
{
  const snd_seq_addr_t * addr;
  
  addr = snd_seq_port_subscribe_get_sender (patch->sub);
  
  return addr->port;
}

unsigned char
alsa_patch_get_dest_client      (const alsa_patch_t * patch)
{
  const snd_seq_addr_t * addr;
  
  addr = snd_seq_port_subscribe_get_dest (patch->sub);
  
  return addr->client;
}
unsigned char
alsa_patch_get_dest_port        (const alsa_patch_t * patch)
{
  const snd_seq_addr_t * addr;
  
  addr = snd_seq_port_subscribe_get_dest (patch->sub);
  
  return addr->port;
}

void
alsa_patch_create_xml (alsa_patch_t * patch, xmlNodePtr parent)
{
  xmlNodePtr patchxml;
  char str[37];

  patchxml = xmlNewChild (parent, NULL, BAD_CAST "alsa_patch", NULL);

  if (uuid_is_null (patch->src_id))
    {
      sprintf (str, "%d", (int) snd_seq_port_subscribe_get_sender(patch->sub)->client);
      xmlNewChild (patchxml, NULL, BAD_CAST "src_client", BAD_CAST str);
    }
  else
    {
      uuid_unparse (patch->src_id, str);
      xmlNewChild (patchxml, NULL, BAD_CAST "src_client_id", BAD_CAST str);
    }

  sprintf (str, "%d", (int) snd_seq_port_subscribe_get_sender(patch->sub)->port);
  xmlNewChild (patchxml, NULL, BAD_CAST "src_port", BAD_CAST str);


  if (uuid_is_null (patch->dest_id))
    {
      sprintf (str, "%d", (int) snd_seq_port_subscribe_get_dest(patch->sub)->client);
      xmlNewChild (patchxml, NULL, BAD_CAST "dest_client", BAD_CAST str);
    }
  else
    {
      uuid_unparse (patch->dest_id, str);
      xmlNewChild (patchxml, NULL, BAD_CAST "dest_client_id", BAD_CAST str);
    }

  sprintf (str, "%d", (int) snd_seq_port_subscribe_get_dest(patch->sub)->port);
  xmlNewChild (patchxml, NULL, BAD_CAST "dest_port", BAD_CAST str);


  sprintf (str, "%d", snd_seq_port_subscribe_get_queue(patch->sub));
  xmlNewChild (patchxml, NULL, BAD_CAST "queue", BAD_CAST str);

  sprintf (str, "%d", snd_seq_port_subscribe_get_exclusive(patch->sub));
  xmlNewChild (patchxml, NULL, BAD_CAST "exclusive", BAD_CAST str);

  sprintf (str, "%d", snd_seq_port_subscribe_get_time_update(patch->sub));
  xmlNewChild (patchxml, NULL, BAD_CAST "time_update", BAD_CAST str);

  sprintf (str, "%d", snd_seq_port_subscribe_get_time_real(patch->sub));
  xmlNewChild (patchxml, NULL, BAD_CAST "time_real", BAD_CAST str);
}

void
alsa_patch_parse_xml      (alsa_patch_t * patch, xmlNodePtr parent)
{
  xmlNodePtr xmlnode;
  xmlChar * content;
  snd_seq_addr_t addr;
  const snd_seq_addr_t * addrptr;

  for (xmlnode = parent->children; xmlnode; xmlnode = xmlnode->next)
    {
      if (strcmp (CAST_BAD (xmlnode->name), "src_client") == 0)
      {
        content = xmlNodeGetContent (xmlnode);
        addrptr = snd_seq_port_subscribe_get_sender (patch->sub);
        addr.client =  strtoul (CAST_BAD content, NULL, 10);
        addr.port = addrptr->port;
        snd_seq_port_subscribe_set_sender (patch->sub, &addr);
        xmlFree (content);
      }
      else if (strcmp (CAST_BAD (xmlnode->name), "src_client_id") == 0)
      {
        content = xmlNodeGetContent (xmlnode);
        uuid_parse (CAST_BAD content, patch->src_id);
        xmlFree (content);
      }
      else if (strcmp (CAST_BAD (xmlnode->name), "src_port") == 0)
      {
        content = xmlNodeGetContent (xmlnode);
        addrptr = snd_seq_port_subscribe_get_sender (patch->sub);
        addr.port =  strtoul (CAST_BAD content, NULL, 10);
        addr.client = addrptr->client;
        snd_seq_port_subscribe_set_sender (patch->sub, &addr);
        xmlFree (content);
      }
      else if (strcmp (CAST_BAD (xmlnode->name), "dest_client") == 0)
      {
        content = xmlNodeGetContent (xmlnode);
        addrptr = snd_seq_port_subscribe_get_dest (patch->sub);
        addr.client =  strtoul (CAST_BAD content, NULL, 10);
        addr.port = addrptr->port;
        snd_seq_port_subscribe_set_dest (patch->sub, &addr);
        xmlFree (content);
      }
      else if (strcmp (CAST_BAD (xmlnode->name), "dest_client_id") == 0)
      {
        content = xmlNodeGetContent (xmlnode);
        uuid_parse (CAST_BAD content, patch->dest_id);
        xmlFree (content);
      }
      else if (strcmp (CAST_BAD (xmlnode->name), "dest_port") == 0)
      {
        content = xmlNodeGetContent (xmlnode);
        addrptr = snd_seq_port_subscribe_get_dest (patch->sub);
        addr.port =  strtoul (CAST_BAD content, NULL, 10);
        addr.client = addrptr->client;
        snd_seq_port_subscribe_set_dest (patch->sub, &addr);
        xmlFree (content);
      }
      else if (strcmp (CAST_BAD (xmlnode->name), "queue") == 0)
      {
        content = xmlNodeGetContent (xmlnode);
        snd_seq_port_subscribe_set_queue (patch->sub, strtoul (CAST_BAD content, NULL, 10));
        xmlFree (content);
      }
      else if (strcmp (CAST_BAD (xmlnode->name), "exclusive") == 0)
      {
        content = xmlNodeGetContent (xmlnode);
        snd_seq_port_subscribe_set_exclusive (patch->sub, strtoul (CAST_BAD content, NULL, 10));
        xmlFree (content);
      }
      else if (strcmp (CAST_BAD (xmlnode->name), "time_update") == 0)
      {
        content = xmlNodeGetContent (xmlnode);
        snd_seq_port_subscribe_set_time_update (patch->sub, strtoul (CAST_BAD content, NULL, 10));
        xmlFree (content);
      }
      else if (strcmp (CAST_BAD (xmlnode->name), "time_real") == 0)
      {
        content = xmlNodeGetContent (xmlnode);
        snd_seq_port_subscribe_set_time_real (patch->sub, strtoul (CAST_BAD content, NULL, 10));
        xmlFree (content);
      }
    }
}

const char *
alsa_patch_get_desc (alsa_patch_t * patch)
{
  static char desc[256];
  char src_client[37];
  char dest_client[37];

  if (uuid_is_null (patch->src_id))
    sprintf (src_client, "%d", (int) snd_seq_port_subscribe_get_sender(patch->sub)->client);
  else
    uuid_unparse (patch->src_id, src_client);

  if (uuid_is_null (patch->dest_id))
    sprintf (dest_client, "%d", (int) snd_seq_port_subscribe_get_dest(patch->sub)->client);
  else
    uuid_unparse (patch->dest_id, dest_client);

  sprintf (desc, "%s:%d -> %s:%d <queue=%d%s%s%s>",
         src_client,
         (int) snd_seq_port_subscribe_get_sender(patch->sub)->port,
         dest_client,
         (int) snd_seq_port_subscribe_get_dest(patch->sub)->port,
         snd_seq_port_subscribe_get_queue(patch->sub),
         snd_seq_port_subscribe_get_exclusive(patch->sub) ? ",exclusive" : "",
         snd_seq_port_subscribe_get_time_update(patch->sub) ? ",time_update" : "",
         snd_seq_port_subscribe_get_time_real(patch->sub) ? ",time_real" : "");

  return desc;
}

int
alsa_patch_compare (alsa_patch_t * a, alsa_patch_t * b)
{
  const snd_seq_addr_t * addr_a, * addr_b;

  addr_a = snd_seq_port_subscribe_get_sender (a->sub);
  addr_b = snd_seq_port_subscribe_get_sender (b->sub);
  if (addr_a->client != addr_b->client || addr_a->port != addr_b->port)
    return 1;

  addr_a = snd_seq_port_subscribe_get_dest (a->sub);
  addr_b = snd_seq_port_subscribe_get_dest (b->sub);
  if (addr_a->client != addr_b->client || addr_a->port != addr_b->port)
    return 1;

  if  ((snd_seq_port_subscribe_get_queue       (a->sub) !=
      snd_seq_port_subscribe_get_queue       (b->sub)   ) ||
       (snd_seq_port_subscribe_get_exclusive   (a->sub) !=
      snd_seq_port_subscribe_get_exclusive   (b->sub)   ) ||
       (snd_seq_port_subscribe_get_time_update (a->sub) !=
      snd_seq_port_subscribe_get_time_update (b->sub)   ) ||
       (snd_seq_port_subscribe_get_time_real   (a->sub) !=
      snd_seq_port_subscribe_get_time_real   (b->sub)   ) )
    return 1;

  return 0;
}


/* EOF */

Generated by  Doxygen 1.6.0   Back to index