⛏️ index : haiku.git

/*
 * Copyright 2003-2013, Haiku, Inc.
 * Distributed under the terms of the MIT license.
 *
 * Authors:
 *		JΓ©rΓ΄me Duval
 *		FranΓ§ois Revol
 *		Axel DΓΆrfler, axeld@pinc-software.de.
 *		Puck Meerburg, puck@puckipedia.nl
 *		Dario Casalinuovo, b.vitruvio@gmail.com
 */


#include "MixerControl.h"

#include <string.h>

#include <Debug.h>
#include <ParameterWeb.h>


MixerControl::MixerControl(int32 volumeWhich)
	:
	fVolumeWhich(volumeWhich),
	fGainMediaNode(media_node::null),
	fMuteMediaNode(media_node::null),
	fParameterWeb(NULL),
	fMixerParameter(NULL),
	fMuteParameter(NULL),
	fMin(0.0f),
	fMax(0.0f),
	fStep(0.0f),
	fRoster(NULL)
{
	fRoster = BMediaRoster::Roster();
}


MixerControl::~MixerControl()
{
	_Disconnect();
}


bool
MixerControl::Connect(int32 volumeWhich, float* _value, const char** _error)
{
	fVolumeWhich = volumeWhich;

	_Disconnect();

	status_t status = B_OK;
	const char* errorString = NULL;
	if (fRoster == NULL)
		fRoster = BMediaRoster::Roster(&status);

	if (BMediaRoster::IsRunning() && fRoster != NULL
			&& status == B_OK) {
		switch (volumeWhich) {
			case VOLUME_USE_MIXER:
				status = fRoster->GetAudioMixer(&fGainMediaNode);
				break;
			case VOLUME_USE_PHYS_OUTPUT:
				status = fRoster->GetAudioOutput(&fGainMediaNode);
				break;
		}
		if (status == B_OK) {
			status = fRoster->GetParameterWebFor(fGainMediaNode, &fParameterWeb);
			if (status == B_OK) {
				// Finding the Mixer slider in the audio output ParameterWeb
				int32 numParams = fParameterWeb->CountParameters();
				BParameter* p = NULL;
				bool foundMixerLabel = false;
				for (int i = 0; i < numParams; i++) {
					p = fParameterWeb->ParameterAt(i);

					// assume the mute preceeding master gain control
					if (!strcmp(p->Kind(), B_MUTE)) {
						fMuteParameter = p;
						fMuteMediaNode = fMuteParameter->Web()->Node();
					}

					PRINT(("BParameter[%i]: %s\n", i, p->Name()));
					if (volumeWhich == VOLUME_USE_MIXER) {
						if (!strcmp(p->Kind(), B_MASTER_GAIN))
							break;
					} else if (volumeWhich == VOLUME_USE_PHYS_OUTPUT) {
						/* not all cards use the same name, and
						 * they don't seem to use Kind() == B_MASTER_GAIN
						 */
						if (!strcmp(p->Kind(), B_MASTER_GAIN))
							break;
						PRINT(("not MASTER_GAIN \n"));

						/* some audio card
						 */
						if (!strcmp(p->Name(), "Master"))
							break;
						PRINT(("not 'Master' \n"));

						/* some Ensonic card have all controls names 'Volume', so
						 * need to fint the one that has the 'Mixer' text label
						 */
						if (foundMixerLabel && !strcmp(p->Name(), "Volume"))
							break;
						if (!strcmp(p->Name(), "Mixer"))
							foundMixerLabel = true;
						PRINT(("not 'Mixer' \n"));
					}
#if 0
					//if (!strcmp(p->Name(), "Master")) {
					if (!strcmp(p->Kind(), B_MASTER_GAIN)) {
						for (; i < numParams; i++) {
							p = fParamWeb->ParameterAt(i);
							if (strcmp(p->Kind(), B_MASTER_GAIN))
								p = NULL;
							else
								break;
						}
						break;
					} else
						p = NULL;
#endif
					p = NULL;
				}
				if (p == NULL) {
					errorString = volumeWhich ? "Could not find the soundcard"
						: "Could not find the mixer";
				} else if (p->Type() != BParameter::B_CONTINUOUS_PARAMETER) {
					errorString = volumeWhich ? "Soundcard control unknown"
						: "Mixer control unknown";
				} else {
					fMixerParameter = static_cast<BContinuousParameter*>(p);
					fMin = fMixerParameter->MinValue();
					fMax = fMixerParameter->MaxValue();
					fStep = fMixerParameter->ValueStep();

					if (_value != NULL) {
						float volume;
						bigtime_t lastChange;
						size_t size = sizeof(float);
						fMixerParameter->GetValue(&volume, &size, &lastChange);

						*_value = volume;
					}
				}
			} else {
				errorString = "No parameter web";
				fParameterWeb = NULL;
			}
		} else
			errorString = volumeWhich ? "No Audio output" : "No Mixer";

	} else
		errorString = "Media services not running";

	if (status != B_OK) {
		_Disconnect();
		fMuteMediaNode = media_node::null;
	}

	if (errorString) {
		fprintf(stderr, "MixerControl: %s.\n", errorString);
		if (_error)
			*_error = errorString;
	}
	if (fMixerParameter == NULL && _value != NULL)
		*_value = 0;

	return errorString == NULL;
}


bool
MixerControl::Connected()
{
	return fGainMediaNode != media_node::null;
}


int32
MixerControl::VolumeWhich() const
{
	return fVolumeWhich;
}


void
MixerControl::SetMute(bool muted)
{
	if (fMuteParameter == NULL)
		return;

	int32 mute = muted ? 1 : 0;
	fMuteParameter->SetValue(&mute, sizeof(int32), system_time());
}


bool
MixerControl::Mute()
{
	if (fMuteParameter == NULL)
		return false;

	int32 mute = 0;
	bigtime_t lastChange = 0;
	size_t size = sizeof(int32);
	fMuteParameter->GetValue(&mute, &size, &lastChange);
	return mute != 0;
}


float
MixerControl::Volume() const
{
	if (fMixerParameter == NULL)
		return 0.0f;

	float volume = 0;
	bigtime_t lastChange;
	size_t size = sizeof(float);
	fMixerParameter->GetValue(&volume, &size, &lastChange);

	return volume;
}


void
MixerControl::SetVolume(float volume)
{
	if (fMixerParameter == NULL)
		return;

	if (volume < fMin)
		volume = fMin;
	else if (volume > fMax)
		volume = fMax;

	if (volume != Volume())
		fMixerParameter->SetValue(&volume, sizeof(float), system_time());
}


void
MixerControl::ChangeVolumeBy(float value)
{
	if (fMixerParameter == NULL || value == 0.0f)
		return;

	float volume = Volume();
	SetVolume(volume + value);
}


void
MixerControl::_Disconnect()
{
	delete fParameterWeb;
	fParameterWeb = NULL;
	fMixerParameter = NULL;

	if (fRoster == NULL)
		fRoster = BMediaRoster::Roster();

	if (fRoster != NULL && fGainMediaNode != media_node::null)
		fRoster->ReleaseNode(fGainMediaNode);

	fGainMediaNode = media_node::null;
}