/**
 * Copyright (C) 2002, 2003 Doug Bell <drbell@users.sourceforge.net>
 *
 * Some mixer routines from mplayer, http://mplayer.sourceforge.net.
 * Copyright (C) 2000-2002. by A'rpi/ESP-team & others
 *
 * 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <stdio.h>
#include <string.h>
#include "alsa_stream.h"
#include "get_media_devices.h"
#include "mixer.h"
#include "tvtimeconf.h"

/**
 * Sets the mixer device and channel.
 */
static int null_set_device( const char *devname, int verbose )
{
    return 0;
}

/**
 * Sets the initial state of the mixer device.
 */
static void null_set_state( int ismuted, int unmute_volume )
{
}

/**
 * Returns the current volume setting.
 */
static int null_get_volume( void )
{
    return 0;
}

/**
 * Returns the volume that would be used to restore the unmute state.
 */
static int null_get_unmute_volume( void )
{
    return 0;
}

/**
 * Tunes the relative volume.
 */
static int null_set_volume( int percentdiff )
{
    return 0;
}

/**
 * Sets the mute state.
 */
static void null_mute( int mute )
{
}

/**
 * Returns true if the mixer is muted.
 */
static int null_ismute( void )
{
    return 0;
}

/**
 * Closes the mixer device if it is open.
 */
static void null_close_device( void )
{
}

/* The null device, which always works. */
static struct mixer null_mixer = {
    .set_device = null_set_device,
    .set_state = null_set_state,
    .get_volume = null_get_volume,
    .get_unmute_volume = null_get_unmute_volume,
    .set_volume = null_set_volume,
    .mute = null_mute,
    .ismute = null_ismute,
    .close_device = null_close_device,
};

/* List of all available access methods.
 * Uses weak symbols: NULL is not linked in. */
static struct mixer *mixers[] = {
    &alsa_mixer,
    &oss_mixer,
    &null_mixer /* LAST */
};
/* The actual access method. */
struct mixer *mixer = &null_mixer;

/* Config settings */
config_t *mixer_cfg;
const char *mixer_capdev;

/**
 * Sets the mixer device and channel.
 * Try each access method until one succeeds.
 */
void mixer_init( config_t *cfg, const char *v4ldev )
{
    const char *devname;
    int i;

    mixer_cfg = cfg;
    devname = config_get_mixer_device( mixer_cfg );
    mixer_capdev = config_get_alsa_inputdev( mixer_cfg );

#ifdef __linux__ /* Because this depends on get_media_devices.c */
    if( !strcmp( mixer_capdev, "auto" ) && v4ldev ) {
	const char *p;
	void *md;

	md = discover_media_devices();
	if( !md ) {
	    fprintf( stderr, "Mixer: cannot enumerate video devices\n" );
	    return;
	}

	p = strrchr( v4ldev, '/' );
	if (p)
	    p++;
	else
	    p = v4ldev;

	p = get_associated_device( md, NULL, MEDIA_SND_CAP, p, MEDIA_V4L_VIDEO );
	if( p ) {
	    mixer_capdev = strdup( p );
	    fprintf( stderr, "Alsa devices: cap: %s (%s), out: %s\n",
		     mixer_capdev, v4ldev,
		     config_get_alsa_outputdev( mixer_cfg ) );
	}

	free_media_devices(md);
    }
#endif

    for (i = 0; i < sizeof(mixers)/sizeof(mixers[0]); i++) {
        mixer = mixers[i];
        if (!mixer)
            continue;
	if( mixer->set_device( devname, config_get_verbose( cfg ) ) == 0 )
            break;
    }

    /* Always start muted, video_input.c will unmute later */
    mixer->set_state( 1, config_get_unmute_volume( mixer_cfg ) );
}

void mixer_exit( void )
{
    alsa_thread_stop();

    if( config_get_mute_on_exit( mixer_cfg ) ) {
	mixer->mute( 1 );
    }

    mixer->close_device();
}

void mixer_mute( int mute )
{
    if( mute ) {
	alsa_thread_stop();
	mixer->mute( 1 );
    } else {
	mixer->mute( 0 );
	alsa_thread_startup( config_get_alsa_outputdev( mixer_cfg ),
			     mixer_capdev, config_get_alsa_latency( mixer_cfg ),
			     stderr, config_get_verbose( mixer_cfg ) );
    }
}
