#ifndef fooalsaucmhfoo
#define fooalsaucmhfoo

/***
  This file is part of PulseAudio.

  Copyright 2011 Wolfson Microelectronics PLC
  Author Margarita Olaya <magi@slimlogic.co.uk>
  Copyright 2012 Feng Wei <wei.feng@freescale.com>, Freescale Ltd.

  PulseAudio is free software; you can redistribute it and/or modify
  it under the terms of the GNU Lesser General Public License as published
  by the Free Software Foundation; either version 2.1 of the License,
  or (at your option) any later version.

  PulseAudio 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 Lesser General Public License
  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
***/

#ifdef HAVE_ALSA_UCM
#include <alsa/use-case.h>
#else
typedef void snd_use_case_mgr_t;
#endif

#include "compat.h"

#include "alsa-mixer.h"

/** For devices: List of verbs, devices or modifiers available */
#define PA_ALSA_PROP_UCM_NAME                       "alsa.ucm.name"

/** For devices: List of supported devices per verb*/
#define PA_ALSA_PROP_UCM_DESCRIPTION                "alsa.ucm.description"

/** For devices: Playback device name e.g PlaybackPCM */
#define PA_ALSA_PROP_UCM_SINK                       "alsa.ucm.sink"

/** For devices: Capture device name e.g CapturePCM*/
#define PA_ALSA_PROP_UCM_SOURCE                     "alsa.ucm.source"

/** For devices: Playback roles */
#define PA_ALSA_PROP_UCM_PLAYBACK_ROLES             "alsa.ucm.playback.roles"

/** For devices: Playback control device name  */
#define PA_ALSA_PROP_UCM_PLAYBACK_CTL_DEVICE        "alsa.ucm.playback.ctldev"

/** For devices: Playback control volume ID string. e.g PlaybackVolume */
#define PA_ALSA_PROP_UCM_PLAYBACK_VOLUME            "alsa.ucm.playback.volume"

/** For devices: Playback switch e.g PlaybackSwitch */
#define PA_ALSA_PROP_UCM_PLAYBACK_SWITCH            "alsa.ucm.playback.switch"

/** For devices: Playback mixer device name  */
#define PA_ALSA_PROP_UCM_PLAYBACK_MIXER_DEVICE      "alsa.ucm.playback.mixer.device"

/** For devices: Playback mixer identifier */
#define PA_ALSA_PROP_UCM_PLAYBACK_MIXER_ELEM        "alsa.ucm.playback.mixer.element"

/** For devices: Playback mixer master identifier */
#define PA_ALSA_PROP_UCM_PLAYBACK_MASTER_ELEM       "alsa.ucm.playback.master.element"

/** For devices: Playback mixer master type */
#define PA_ALSA_PROP_UCM_PLAYBACK_MASTER_TYPE       "alsa.ucm.playback.master.type"

/** For devices: Playback mixer master identifier */
#define PA_ALSA_PROP_UCM_PLAYBACK_MASTER_ID         "alsa.ucm.playback.master.id"

/** For devices: Playback mixer master type */
#define PA_ALSA_PROP_UCM_PLAYBACK_MASTER_TYPE       "alsa.ucm.playback.master.type"

/** For devices: Playback priority */
#define PA_ALSA_PROP_UCM_PLAYBACK_PRIORITY          "alsa.ucm.playback.priority"

/** For devices: Playback rate */
#define PA_ALSA_PROP_UCM_PLAYBACK_RATE              "alsa.ucm.playback.rate"

/** For devices: Playback channels */
#define PA_ALSA_PROP_UCM_PLAYBACK_CHANNELS          "alsa.ucm.playback.channels"

/** For devices: Capture roles */
#define PA_ALSA_PROP_UCM_CAPTURE_ROLES              "alsa.ucm.capture.roles"

/** For devices: Capture control device name  */
#define PA_ALSA_PROP_UCM_CAPTURE_CTL_DEVICE         "alsa.ucm.capture.ctldev"

/** For devices: Capture controls volume ID string. e.g CaptureVolume */
#define PA_ALSA_PROP_UCM_CAPTURE_VOLUME             "alsa.ucm.capture.volume"

/** For devices: Capture switch e.g CaptureSwitch */
#define PA_ALSA_PROP_UCM_CAPTURE_SWITCH             "alsa.ucm.capture.switch"

/** For devices: Capture mixer device name  */
#define PA_ALSA_PROP_UCM_CAPTURE_MIXER_DEVICE       "alsa.ucm.capture.mixer.device"

/** For devices: Capture mixer identifier */
#define PA_ALSA_PROP_UCM_CAPTURE_MIXER_ELEM         "alsa.ucm.capture.mixer.element"

/** For devices: Capture mixer identifier */
#define PA_ALSA_PROP_UCM_CAPTURE_MASTER_ELEM        "alsa.ucm.capture.master.element"

/** For devices: Capture mixer identifier */
#define PA_ALSA_PROP_UCM_CAPTURE_MASTER_TYPE        "alsa.ucm.capture.master.type"

/** For devices: Capture mixer identifier */
#define PA_ALSA_PROP_UCM_CAPTURE_MASTER_ID          "alsa.ucm.capture.master.id"

/** For devices: Capture mixer identifier */
#define PA_ALSA_PROP_UCM_CAPTURE_MASTER_TYPE        "alsa.ucm.capture.master.type"

/** For devices: Capture priority */
#define PA_ALSA_PROP_UCM_CAPTURE_PRIORITY           "alsa.ucm.capture.priority"

/** For devices: Capture rate */
#define PA_ALSA_PROP_UCM_CAPTURE_RATE               "alsa.ucm.capture.rate"

/** For devices: Capture channels */
#define PA_ALSA_PROP_UCM_CAPTURE_CHANNELS           "alsa.ucm.capture.channels"

/** For devices: Quality of Service */
#define PA_ALSA_PROP_UCM_QOS                        "alsa.ucm.qos"

/** For devices: The modifier (if any) that this device corresponds to */
#define PA_ALSA_PROP_UCM_MODIFIER "alsa.ucm.modifier"

/* Corresponds to the "JackCTL" UCM value. */
#define PA_ALSA_PROP_UCM_JACK_DEVICE		    "alsa.ucm.jack_device"

/* Corresponds to the "JackControl" UCM value. */
#define PA_ALSA_PROP_UCM_JACK_CONTROL               "alsa.ucm.jack_control"

/* Corresponds to the "JackHWMute" UCM value. */
#define PA_ALSA_PROP_UCM_JACK_HW_MUTE               "alsa.ucm.jack_hw_mute"

typedef struct pa_alsa_ucm_verb pa_alsa_ucm_verb;
typedef struct pa_alsa_ucm_modifier pa_alsa_ucm_modifier;
typedef struct pa_alsa_ucm_device pa_alsa_ucm_device;
typedef struct pa_alsa_ucm_config pa_alsa_ucm_config;
typedef struct pa_alsa_ucm_mapping_context pa_alsa_ucm_mapping_context;
typedef struct pa_alsa_ucm_profile_context pa_alsa_ucm_profile_context;
typedef struct pa_alsa_ucm_port_data pa_alsa_ucm_port_data;
typedef struct pa_alsa_ucm_volume pa_alsa_ucm_volume;
typedef struct pa_alsa_ucm_split pa_alsa_ucm_split;

int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index);
pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map);
int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_profile *new_profile, pa_alsa_profile *old_profile);

int pa_alsa_ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, const char *verb_desc, pa_alsa_ucm_verb **p_verb);

void pa_alsa_ucm_add_ports(
        pa_hashmap **hash,
        pa_proplist *proplist,
        pa_alsa_ucm_mapping_context *context,
        bool is_sink,
        pa_card *card,
        snd_pcm_t *pcm_handle,
        bool ignore_dB);
void pa_alsa_ucm_add_port(
        pa_hashmap *hash,
        pa_alsa_ucm_mapping_context *context,
        bool is_sink,
        pa_hashmap *ports,
        pa_card_profile *cp,
        pa_core *core);
int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port);

void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm);
void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context);

void pa_alsa_ucm_roled_stream_begin(pa_alsa_ucm_config *ucm, const char *role, pa_direction_t dir);
void pa_alsa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm, const char *role, pa_direction_t dir);

/* UCM - Use Case Manager is available on some audio cards */

struct pa_alsa_ucm_split {
    /* UCM SplitPCM channel remapping */
    bool leader;
    int hw_channels;
    int channels;
    int idx[PA_CHANNELS_MAX];
    enum snd_pcm_chmap_position pos[PA_CHANNELS_MAX];
    bool broken;
};

struct pa_alsa_ucm_device {
    PA_LLIST_FIELDS(pa_alsa_ucm_device);

    pa_proplist *proplist;

    pa_device_port_type_t type;

    unsigned playback_priority;
    unsigned capture_priority;

    unsigned playback_rate;
    unsigned capture_rate;

    unsigned playback_channels;
    unsigned capture_channels;

    /* These may be different per verb, so we store this as a hashmap of verb -> volume_control. We might eventually want to
     * make this a hashmap of verb -> per-verb-device-properties-struct. */
    pa_hashmap *playback_volumes;
    pa_hashmap *capture_volumes;

    pa_alsa_mapping *playback_mapping;
    pa_alsa_mapping *capture_mapping;

    pa_idxset *conflicting_devices;
    pa_idxset *supported_devices;

    /* One device may be part of multiple ports, since each device has
     * a dedicated port, and in addition to that we sometimes generate ports
     * that represent combinations of devices. */
    pa_dynarray *ucm_ports; /* struct ucm_port */

    pa_alsa_jack *jack;
    pa_dynarray *hw_mute_jacks; /* pa_alsa_jack */
    pa_available_t available;

    char *eld_mixer_device_name;
    int eld_device;

    pa_alsa_ucm_split *playback_split;
    pa_alsa_ucm_split *capture_split;
};

void pa_alsa_ucm_device_update_available(pa_alsa_ucm_device *device);

struct pa_alsa_ucm_modifier {
    PA_LLIST_FIELDS(pa_alsa_ucm_modifier);

    pa_proplist *proplist;

    pa_idxset *conflicting_devices;
    pa_idxset *supported_devices;

    pa_direction_t action_direction;

    char *media_role;

    /* Non-NULL if the modifier has its own PlaybackPCM/CapturePCM */
    pa_alsa_mapping *playback_mapping;
    pa_alsa_mapping *capture_mapping;

    /* Count how many role matched streams are running */
    int enabled_counter;
};

struct pa_alsa_ucm_verb {
    PA_LLIST_FIELDS(pa_alsa_ucm_verb);

    pa_proplist *proplist;
    unsigned priority;

    PA_LLIST_HEAD(pa_alsa_ucm_device, devices);
    PA_LLIST_HEAD(pa_alsa_ucm_modifier, modifiers);
};

struct pa_alsa_ucm_config {
    pa_sample_spec default_sample_spec;
    pa_channel_map default_channel_map;
    unsigned default_fragment_size_msec;
    unsigned default_n_fragments;
    bool split_enable;

    snd_use_case_mgr_t *ucm_mgr;
    pa_alsa_ucm_verb *active_verb;
    char *alib_prefix;

    pa_hashmap *mixers;
    PA_LLIST_HEAD(pa_alsa_ucm_verb, verbs);
    PA_LLIST_HEAD(pa_alsa_jack, jacks);
};

struct pa_alsa_ucm_mapping_context {
    pa_alsa_ucm_config *ucm;
    pa_direction_t direction;

    pa_alsa_ucm_device *ucm_device;
    pa_alsa_ucm_modifier *ucm_modifier;
};

struct pa_alsa_ucm_profile_context {
    pa_alsa_ucm_verb *verb;
};

struct pa_alsa_ucm_port_data {
    pa_alsa_ucm_config *ucm;
    pa_device_port *core_port;

    pa_alsa_ucm_device *device;

    /* verb name -> pa_alsa_path for volume control */
    pa_hashmap *paths;
    /* Current path, set when activating verb */
    pa_alsa_path *path;

    /* ELD info */
    char *eld_mixer_device_name;
    int eld_device; /* PCM device number */
};

long pa_alsa_ucm_port_device_status(pa_alsa_ucm_port_data *data);

struct pa_alsa_ucm_volume {
    char *mixer_elem;	/* mixer element identifier */
    char *master_elem;	/* master mixer element identifier */
    char *master_type;
};

#endif
