<commit_before>/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "WebRuntimeFeatures.h"

#include "RuntimeEnabledFeatures.h"
#include "WebMediaPlayerClientImpl.h"

using namespace WebCore;

namespace blink {

void WebRuntimeFeatures::enableExperimentalFeatures(bool enable)
{
    RuntimeEnabledFeatures::setExperimentalFeaturesEnabled(enable);
}

void WebRuntimeFeatures::enableBleedingEdgeFastPaths(bool enable)
{
    ASSERT(enable);
    RuntimeEnabledFeatures::setBleedingEdgeFastPathsEnabled(enable);
    RuntimeEnabledFeatures::setSubpixelFontScalingEnabled(enable || RuntimeEnabledFeatures::subpixelFontScalingEnabled());
    RuntimeEnabledFeatures::setCSSWillChangeEnabled(enable);
}

void WebRuntimeFeatures::enableTestOnlyFeatures(bool enable)
{
    RuntimeEnabledFeatures::setTestFeaturesEnabled(enable);
}

void WebRuntimeFeatures::enableApplicationCache(bool enable)
{
    RuntimeEnabledFeatures::setApplicationCacheEnabled(enable);
}

void WebRuntimeFeatures::enableDatabase(bool enable)
{
    RuntimeEnabledFeatures::setDatabaseEnabled(enable);
}

void WebRuntimeFeatures::enableDialogElement(bool enable)
{
    RuntimeEnabledFeatures::setDialogElementEnabled(enable);
}

void WebRuntimeFeatures::enableEncryptedMedia(bool enable)
{
    RuntimeEnabledFeatures::setEncryptedMediaEnabled(enable);
    // FIXME: Hack to allow MediaKeyError to be enabled for either version.
    RuntimeEnabledFeatures::setEncryptedMediaAnyVersionEnabled(
        RuntimeEnabledFeatures::encryptedMediaEnabled()
        || RuntimeEnabledFeatures::prefixedEncryptedMediaEnabled());
}

bool WebRuntimeFeatures::isEncryptedMediaEnabled()
{
    return RuntimeEnabledFeatures::encryptedMediaEnabled();
}

void WebRuntimeFeatures::enablePrefixedEncryptedMedia(bool enable)
{
    RuntimeEnabledFeatures::setPrefixedEncryptedMediaEnabled(enable);
    // FIXME: Hack to allow MediaKeyError to be enabled for either version.
    RuntimeEnabledFeatures::setEncryptedMediaAnyVersionEnabled(
        RuntimeEnabledFeatures::encryptedMediaEnabled()
        || RuntimeEnabledFeatures::prefixedEncryptedMediaEnabled());
}

bool WebRuntimeFeatures::isPrefixedEncryptedMediaEnabled()
{
    return RuntimeEnabledFeatures::prefixedEncryptedMediaEnabled();
}

void WebRuntimeFeatures::enableDirectWrite(bool enable)
{
    RuntimeEnabledFeatures::setDirectWriteEnabled(enable);
    RuntimeEnabledFeatures::setSubpixelFontScalingEnabled(enable || RuntimeEnabledFeatures::subpixelFontScalingEnabled());
}

void WebRuntimeFeatures::enableExperimentalCanvasFeatures(bool enable)
{
    RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(enable);
}

void WebRuntimeFeatures::enableFastTextAutosizing(bool enable)
{
    RuntimeEnabledFeatures::setFastTextAutosizingEnabled(enable);
}

void WebRuntimeFeatures::enableFileSystem(bool enable)
{
    RuntimeEnabledFeatures::setFileSystemEnabled(enable);
}

void WebRuntimeFeatures::enableGamepad(bool enable)
{
    RuntimeEnabledFeatures::setGamepadEnabled(enable);
}

void WebRuntimeFeatures::enableLazyLayout(bool enable)
{
    // FIXME: Remove this once Chromium stops calling this.
}

void WebRuntimeFeatures::enableLocalStorage(bool enable)
{
    RuntimeEnabledFeatures::setLocalStorageEnabled(enable);
}

void WebRuntimeFeatures::enableMediaPlayer(bool enable)
{
    RuntimeEnabledFeatures::setMediaEnabled(enable);
}

void WebRuntimeFeatures::enableWebKitMediaSource(bool enable)
{
    RuntimeEnabledFeatures::setWebKitMediaSourceEnabled(enable);
}

void WebRuntimeFeatures::enableMediaSource(bool enable)
{
    RuntimeEnabledFeatures::setMediaSourceEnabled(enable);
}

void WebRuntimeFeatures::enableMediaStream(bool enable)
{
    RuntimeEnabledFeatures::setMediaStreamEnabled(enable);
}

void WebRuntimeFeatures::enableNotifications(bool enable)
{
    RuntimeEnabledFeatures::setNotificationsEnabled(enable);
}

void WebRuntimeFeatures::enableNavigatorContentUtils(bool enable)
{
    RuntimeEnabledFeatures::setNavigatorContentUtilsEnabled(enable);
}

void WebRuntimeFeatures::enableOrientationEvent(bool enable)
{
    RuntimeEnabledFeatures::setOrientationEventEnabled(enable);
}

void WebRuntimeFeatures::enablePagePopup(bool enable)
{
    RuntimeEnabledFeatures::setPagePopupEnabled(enable);
}

void WebRuntimeFeatures::enablePeerConnection(bool enable)
{
    RuntimeEnabledFeatures::setPeerConnectionEnabled(enable);
}

void WebRuntimeFeatures::enableRequestAutocomplete(bool enable)
{
    RuntimeEnabledFeatures::setRequestAutocompleteEnabled(enable);
}

void WebRuntimeFeatures::enableScriptedSpeech(bool enable)
{
    RuntimeEnabledFeatures::setScriptedSpeechEnabled(enable);
}

void WebRuntimeFeatures::enableServiceWorker(bool enable)
{
    RuntimeEnabledFeatures::setServiceWorkerEnabled(enable);
}

void WebRuntimeFeatures::enableSessionStorage(bool enable)
{
    RuntimeEnabledFeatures::setSessionStorageEnabled(enable);
}

void WebRuntimeFeatures::enableSpeechInput(bool enable)
{
    RuntimeEnabledFeatures::setSpeechInputEnabled(enable);
}

void WebRuntimeFeatures::enableSpeechSynthesis(bool enable)
{
    RuntimeEnabledFeatures::setSpeechSynthesisEnabled(enable);
}

void WebRuntimeFeatures::enableTouch(bool enable)
{
    RuntimeEnabledFeatures::setTouchEnabled(enable);
}

void WebRuntimeFeatures::enableTouchIconLoading(bool enable)
{
    RuntimeEnabledFeatures::setTouchIconLoadingEnabled(enable);
}

void WebRuntimeFeatures::enableWebAnimationsCSS(bool enable)
{
    // FIXME: Remove this method once the runtime flags are removed from Chromium.
    ASSERT(enable);
}

void WebRuntimeFeatures::enableWebAnimationsSVG(bool enable)
{
    RuntimeEnabledFeatures::setWebAnimationsSVGEnabled(enable);
}

void WebRuntimeFeatures::enableWebAudio(bool enable)
{
    RuntimeEnabledFeatures::setWebAudioEnabled(enable);
}

void WebRuntimeFeatures::enableWebGLDraftExtensions(bool enable)
{
    RuntimeEnabledFeatures::setWebGLDraftExtensionsEnabled(enable);
}

void WebRuntimeFeatures::enableWebMIDI(bool enable)
{
    return RuntimeEnabledFeatures::setWebMIDIEnabled(enable);
}

void WebRuntimeFeatures::enableHTMLImports(bool enable)
{
    RuntimeEnabledFeatures::setHTMLImportsEnabled(enable);
}

void WebRuntimeFeatures::enableXSLT(bool enable)
{
    RuntimeEnabledFeatures::setXSLTEnabled(enable);
}

void WebRuntimeFeatures::enableOverlayScrollbars(bool enable)
{
    RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(enable);
}

void WebRuntimeFeatures::enableOverlayFullscreenVideo(bool enable)
{
    RuntimeEnabledFeatures::setOverlayFullscreenVideoEnabled(enable);
}

void WebRuntimeFeatures::enableSharedWorker(bool enable)
{
    RuntimeEnabledFeatures::setSharedWorkerEnabled(enable);
}

void WebRuntimeFeatures::enableRepaintAfterLayout(bool enable)
{
    RuntimeEnabledFeatures::setRepaintAfterLayoutEnabled(enable);
}

void WebRuntimeFeatures::enableExperimentalWebSocket(bool enable)
{
    RuntimeEnabledFeatures::setExperimentalWebSocketEnabled(enable);
}

void WebRuntimeFeatures::enableTargetedStyleRecalc(bool enable)
{
    RuntimeEnabledFeatures::setTargetedStyleRecalcEnabled(enable);
}

} // namespace blink
<commit_msg>Add Web Animations API to bleeding edge fast path<commit_after>/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "WebRuntimeFeatures.h"

#include "RuntimeEnabledFeatures.h"
#include "WebMediaPlayerClientImpl.h"

using namespace WebCore;

namespace blink {

void WebRuntimeFeatures::enableExperimentalFeatures(bool enable)
{
    RuntimeEnabledFeatures::setExperimentalFeaturesEnabled(enable);
}

void WebRuntimeFeatures::enableBleedingEdgeFastPaths(bool enable)
{
    ASSERT(enable);
    RuntimeEnabledFeatures::setBleedingEdgeFastPathsEnabled(enable);
    RuntimeEnabledFeatures::setSubpixelFontScalingEnabled(enable || RuntimeEnabledFeatures::subpixelFontScalingEnabled());
    RuntimeEnabledFeatures::setCSSWillChangeEnabled(enable);
    RuntimeEnabledFeatures::setWebAnimationsAPIEnabled(enable);
}

void WebRuntimeFeatures::enableTestOnlyFeatures(bool enable)
{
    RuntimeEnabledFeatures::setTestFeaturesEnabled(enable);
}

void WebRuntimeFeatures::enableApplicationCache(bool enable)
{
    RuntimeEnabledFeatures::setApplicationCacheEnabled(enable);
}

void WebRuntimeFeatures::enableDatabase(bool enable)
{
    RuntimeEnabledFeatures::setDatabaseEnabled(enable);
}

void WebRuntimeFeatures::enableDialogElement(bool enable)
{
    RuntimeEnabledFeatures::setDialogElementEnabled(enable);
}

void WebRuntimeFeatures::enableEncryptedMedia(bool enable)
{
    RuntimeEnabledFeatures::setEncryptedMediaEnabled(enable);
    // FIXME: Hack to allow MediaKeyError to be enabled for either version.
    RuntimeEnabledFeatures::setEncryptedMediaAnyVersionEnabled(
        RuntimeEnabledFeatures::encryptedMediaEnabled()
        || RuntimeEnabledFeatures::prefixedEncryptedMediaEnabled());
}

bool WebRuntimeFeatures::isEncryptedMediaEnabled()
{
    return RuntimeEnabledFeatures::encryptedMediaEnabled();
}

void WebRuntimeFeatures::enablePrefixedEncryptedMedia(bool enable)
{
    RuntimeEnabledFeatures::setPrefixedEncryptedMediaEnabled(enable);
    // FIXME: Hack to allow MediaKeyError to be enabled for either version.
    RuntimeEnabledFeatures::setEncryptedMediaAnyVersionEnabled(
        RuntimeEnabledFeatures::encryptedMediaEnabled()
        || RuntimeEnabledFeatures::prefixedEncryptedMediaEnabled());
}

bool WebRuntimeFeatures::isPrefixedEncryptedMediaEnabled()
{
    return RuntimeEnabledFeatures::prefixedEncryptedMediaEnabled();
}

void WebRuntimeFeatures::enableDirectWrite(bool enable)
{
    RuntimeEnabledFeatures::setDirectWriteEnabled(enable);
    RuntimeEnabledFeatures::setSubpixelFontScalingEnabled(enable || RuntimeEnabledFeatures::subpixelFontScalingEnabled());
}

void WebRuntimeFeatures::enableExperimentalCanvasFeatures(bool enable)
{
    RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(enable);
}

void WebRuntimeFeatures::enableFastTextAutosizing(bool enable)
{
    RuntimeEnabledFeatures::setFastTextAutosizingEnabled(enable);
}

void WebRuntimeFeatures::enableFileSystem(bool enable)
{
    RuntimeEnabledFeatures::setFileSystemEnabled(enable);
}

void WebRuntimeFeatures::enableGamepad(bool enable)
{
    RuntimeEnabledFeatures::setGamepadEnabled(enable);
}

void WebRuntimeFeatures::enableLazyLayout(bool enable)
{
    // FIXME: Remove this once Chromium stops calling this.
}

void WebRuntimeFeatures::enableLocalStorage(bool enable)
{
    RuntimeEnabledFeatures::setLocalStorageEnabled(enable);
}

void WebRuntimeFeatures::enableMediaPlayer(bool enable)
{
    RuntimeEnabledFeatures::setMediaEnabled(enable);
}

void WebRuntimeFeatures::enableWebKitMediaSource(bool enable)
{
    RuntimeEnabledFeatures::setWebKitMediaSourceEnabled(enable);
}

void WebRuntimeFeatures::enableMediaSource(bool enable)
{
    RuntimeEnabledFeatures::setMediaSourceEnabled(enable);
}

void WebRuntimeFeatures::enableMediaStream(bool enable)
{
    RuntimeEnabledFeatures::setMediaStreamEnabled(enable);
}

void WebRuntimeFeatures::enableNotifications(bool enable)
{
    RuntimeEnabledFeatures::setNotificationsEnabled(enable);
}

void WebRuntimeFeatures::enableNavigatorContentUtils(bool enable)
{
    RuntimeEnabledFeatures::setNavigatorContentUtilsEnabled(enable);
}

void WebRuntimeFeatures::enableOrientationEvent(bool enable)
{
    RuntimeEnabledFeatures::setOrientationEventEnabled(enable);
}

void WebRuntimeFeatures::enablePagePopup(bool enable)
{
    RuntimeEnabledFeatures::setPagePopupEnabled(enable);
}

void WebRuntimeFeatures::enablePeerConnection(bool enable)
{
    RuntimeEnabledFeatures::setPeerConnectionEnabled(enable);
}

void WebRuntimeFeatures::enableRequestAutocomplete(bool enable)
{
    RuntimeEnabledFeatures::setRequestAutocompleteEnabled(enable);
}

void WebRuntimeFeatures::enableScriptedSpeech(bool enable)
{
    RuntimeEnabledFeatures::setScriptedSpeechEnabled(enable);
}

void WebRuntimeFeatures::enableServiceWorker(bool enable)
{
    RuntimeEnabledFeatures::setServiceWorkerEnabled(enable);
}

void WebRuntimeFeatures::enableSessionStorage(bool enable)
{
    RuntimeEnabledFeatures::setSessionStorageEnabled(enable);
}

void WebRuntimeFeatures::enableSpeechInput(bool enable)
{
    RuntimeEnabledFeatures::setSpeechInputEnabled(enable);
}

void WebRuntimeFeatures::enableSpeechSynthesis(bool enable)
{
    RuntimeEnabledFeatures::setSpeechSynthesisEnabled(enable);
}

void WebRuntimeFeatures::enableTouch(bool enable)
{
    RuntimeEnabledFeatures::setTouchEnabled(enable);
}

void WebRuntimeFeatures::enableTouchIconLoading(bool enable)
{
    RuntimeEnabledFeatures::setTouchIconLoadingEnabled(enable);
}

void WebRuntimeFeatures::enableWebAnimationsCSS(bool enable)
{
    // FIXME: Remove this method once the runtime flags are removed from Chromium.
    ASSERT(enable);
}

void WebRuntimeFeatures::enableWebAnimationsSVG(bool enable)
{
    RuntimeEnabledFeatures::setWebAnimationsSVGEnabled(enable);
}

void WebRuntimeFeatures::enableWebAudio(bool enable)
{
    RuntimeEnabledFeatures::setWebAudioEnabled(enable);
}

void WebRuntimeFeatures::enableWebGLDraftExtensions(bool enable)
{
    RuntimeEnabledFeatures::setWebGLDraftExtensionsEnabled(enable);
}

void WebRuntimeFeatures::enableWebMIDI(bool enable)
{
    return RuntimeEnabledFeatures::setWebMIDIEnabled(enable);
}

void WebRuntimeFeatures::enableHTMLImports(bool enable)
{
    RuntimeEnabledFeatures::setHTMLImportsEnabled(enable);
}

void WebRuntimeFeatures::enableXSLT(bool enable)
{
    RuntimeEnabledFeatures::setXSLTEnabled(enable);
}

void WebRuntimeFeatures::enableOverlayScrollbars(bool enable)
{
    RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(enable);
}

void WebRuntimeFeatures::enableOverlayFullscreenVideo(bool enable)
{
    RuntimeEnabledFeatures::setOverlayFullscreenVideoEnabled(enable);
}

void WebRuntimeFeatures::enableSharedWorker(bool enable)
{
    RuntimeEnabledFeatures::setSharedWorkerEnabled(enable);
}

void WebRuntimeFeatures::enableRepaintAfterLayout(bool enable)
{
    RuntimeEnabledFeatures::setRepaintAfterLayoutEnabled(enable);
}

void WebRuntimeFeatures::enableExperimentalWebSocket(bool enable)
{
    RuntimeEnabledFeatures::setExperimentalWebSocketEnabled(enable);
}

void WebRuntimeFeatures::enableTargetedStyleRecalc(bool enable)
{
    RuntimeEnabledFeatures::setTargetedStyleRecalcEnabled(enable);
}

} // namespace blink
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "ifaces/audiooutput.h"
#include "factory.h"
#include "audiooutputdevice.h"

#include <kglobal.h>
#include <kinstance.h>
#include <kaboutdata.h>

namespace Phonon
{
PHONON_HEIR_IMPL( AudioOutput, AbstractAudioOutput )

QString AudioOutput::name() const
{
	K_D( const AudioOutput );
	return d->iface() ? d->iface()->name() : d->name;
}

void AudioOutput::setName( const QString& newName )
{
	K_D( AudioOutput );
	if( d->iface() )
		d->iface()->setName( newName );
	else
		d->name = newName;
}

float AudioOutput::volume() const
{
	K_D( const AudioOutput );
	return d->iface() ? d->iface()->volume() : d->volume;
}

void AudioOutput::setVolume( float newVolume )
{
	K_D( AudioOutput );
	if( d->iface() )
		d->iface()->setVolume( newVolume );
	else
		d->volume = newVolume;
}

static const float log10over20 = 0.1151292546497022842; // ln(10) / 20

float AudioOutput::volumeDecibel() const
{
	return -logf( volume() ) / log10over20;
}

void AudioOutput::setVolumeDecibel( float newVolumeDecibel )
{
	setVolume( expf( -newVolumeDecibel * log10over20 ) );
}

Category AudioOutput::category() const
{
	K_D( const AudioOutput );
	return d->category;
}

QString AudioOutput::categoryName() const
{
	K_D( const AudioOutput );
	return Phonon::categoryToString( d->category );
}

void AudioOutput::setCategory( Category c )
{
	K_D( AudioOutput );
	d->category = c;
	//TODO: select the according AudioOutputDevice
}

AudioOutputDevice AudioOutput::outputDevice() const
{
	K_D( const AudioOutput );
	return AudioOutputDevice::fromIndex( d->iface() ? d->iface()->outputDevice() : d->outputDeviceIndex );
}

void AudioOutput::setOutputDevice( const AudioOutputDevice& newAudioOutputDevice )
{
	K_D( AudioOutput );
	if( iface() )
		d->iface()->setOutputDevice( newAudioOutputDevice.index() );
	else
		d->outputDeviceIndex = newAudioOutputDevice.index();
}

bool AudioOutputPrivate::aboutToDeleteIface()
{
	if( iface() )
	{
		name = iface()->name();
		volume = iface()->volume();
	}
	return AbstractAudioOutputPrivate::aboutToDeleteIface();
}

void AudioOutput::setupIface()
{
	K_D( AudioOutput );
	Q_ASSERT( d->iface() );
	AbstractAudioOutput::setupIface();

	connect( d->iface()->qobject(), SIGNAL( volumeChanged( float ) ), SIGNAL( volumeChanged( float ) ) );

	// set up attributes
	d->iface()->setName( d->name );
	d->iface()->setVolume( d->volume );
}

} //namespace Phonon

#include "audiooutput.moc"

// vim: sw=4 ts=4 tw=80 noet
<commit_msg>missing include<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "ifaces/audiooutput.h"
#include "factory.h"
#include "audiooutputdevice.h"

#include <kglobal.h>
#include <kinstance.h>
#include <kaboutdata.h>
#include <cmath>

namespace Phonon
{
PHONON_HEIR_IMPL( AudioOutput, AbstractAudioOutput )

QString AudioOutput::name() const
{
	K_D( const AudioOutput );
	return d->iface() ? d->iface()->name() : d->name;
}

void AudioOutput::setName( const QString& newName )
{
	K_D( AudioOutput );
	if( d->iface() )
		d->iface()->setName( newName );
	else
		d->name = newName;
}

float AudioOutput::volume() const
{
	K_D( const AudioOutput );
	return d->iface() ? d->iface()->volume() : d->volume;
}

void AudioOutput::setVolume( float newVolume )
{
	K_D( AudioOutput );
	if( d->iface() )
		d->iface()->setVolume( newVolume );
	else
		d->volume = newVolume;
}

static const float log10over20 = 0.1151292546497022842; // ln(10) / 20

float AudioOutput::volumeDecibel() const
{
	return -logf( volume() ) / log10over20;
}

void AudioOutput::setVolumeDecibel( float newVolumeDecibel )
{
	setVolume( expf( -newVolumeDecibel * log10over20 ) );
}

Category AudioOutput::category() const
{
	K_D( const AudioOutput );
	return d->category;
}

QString AudioOutput::categoryName() const
{
	K_D( const AudioOutput );
	return Phonon::categoryToString( d->category );
}

void AudioOutput::setCategory( Category c )
{
	K_D( AudioOutput );
	d->category = c;
	//TODO: select the according AudioOutputDevice
}

AudioOutputDevice AudioOutput::outputDevice() const
{
	K_D( const AudioOutput );
	return AudioOutputDevice::fromIndex( d->iface() ? d->iface()->outputDevice() : d->outputDeviceIndex );
}

void AudioOutput::setOutputDevice( const AudioOutputDevice& newAudioOutputDevice )
{
	K_D( AudioOutput );
	if( iface() )
		d->iface()->setOutputDevice( newAudioOutputDevice.index() );
	else
		d->outputDeviceIndex = newAudioOutputDevice.index();
}

bool AudioOutputPrivate::aboutToDeleteIface()
{
	if( iface() )
	{
		name = iface()->name();
		volume = iface()->volume();
	}
	return AbstractAudioOutputPrivate::aboutToDeleteIface();
}

void AudioOutput::setupIface()
{
	K_D( AudioOutput );
	Q_ASSERT( d->iface() );
	AbstractAudioOutput::setupIface();

	connect( d->iface()->qobject(), SIGNAL( volumeChanged( float ) ), SIGNAL( volumeChanged( float ) ) );

	// set up attributes
	d->iface()->setName( d->name );
	d->iface()->setVolume( d->volume );
}

} //namespace Phonon

#include "audiooutput.moc"

// vim: sw=4 ts=4 tw=80 noet
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2008 Renato Araujo Oliveira Filho <renatox@gmail.com>
Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
--------------------------------------------------------------------------*/

#include "OgreRoot.h"
#include "OgreException.h"
#include "OgreLogManager.h"
#include "OgreStringConverter.h"
#include "OgreWindowEventUtilities.h"

#include "OgreGLESPrerequisites.h"
#include "OgreGLESRenderSystem.h"

#include "OgreWin32EGLSupport.h"
#include "OgreWin32EGLWindow.h"
#include "OgreWin32EGLContext.h"

#include <iostream>
#include <algorithm>
#include <climits>

namespace Ogre {
    Win32EGLWindow::Win32EGLWindow(Win32EGLSupport *glsupport)
		: EGLWindow(glsupport)
    {
		mGLSupport = glsupport;
		mNativeDisplay = glsupport->getNativeDisplay();
    }

    Win32EGLWindow::~Win32EGLWindow()
    {
    }

	EGLContext * Win32EGLWindow::createEGLContext() const
	{
		return new Win32EGLContext(mEglDisplay, mGLSupport, mEglConfig, mEglSurface);
	}

	void Win32EGLWindow::getLeftAndTopFromNativeWindow( int & left, int & top, uint width, uint height )
	{

	}

	void Win32EGLWindow::initNativeCreatedWindow(const NameValuePairList *miscParams)
	{

	}

	void Win32EGLWindow::createNativeWindow( int &left, int &top, uint &width, uint &height, String &title )
	{
		// destroy current window, if any
		if (mWindow)
			destroy();

#ifdef OGRE_STATIC_LIB
		HINSTANCE hInst = GetModuleHandle( NULL );
#else
#  if OGRE_DEBUG_MODE == 1
		HINSTANCE hInst = GetModuleHandle("RenderSystem_GLES_d.dll");
#  else
		HINSTANCE hInst = GetModuleHandle("RenderSystem_GLES.dll");
#  endif
#endif

		mWindow = 0;
		mClosed = false;
		mIsDepthBuffered = true;
		mColourDepth = mIsFullScreen? 32 : GetDeviceCaps(GetDC(0), BITSPIXEL);
		HWND parent = 0;
		bool vsync = false;
		String border;
		bool outerSize = false;
		bool hwGamma = false;
		int monitorIndex = -1;
		HMONITOR hMonitor = NULL;

		if (!mIsExternal)
		{
			DWORD		  dwStyle = WS_VISIBLE | WS_CLIPCHILDREN;
			DWORD		  dwStyleEx = 0;
			MONITORINFOEX monitorInfoEx;
			RECT		  rc;

			// If we didn't specified the adapter index, or if it didn't find it
			if (hMonitor == NULL)
			{
				POINT windowAnchorPoint;

				// Fill in anchor point.
				windowAnchorPoint.x = left;
				windowAnchorPoint.y = top;

				// Get the nearest monitor to this window.
				hMonitor = MonitorFromPoint(windowAnchorPoint, MONITOR_DEFAULTTONEAREST);
			}

			// Get the target monitor info
			memset(&monitorInfoEx, 0, sizeof(MONITORINFOEX));
			monitorInfoEx.cbSize = sizeof(MONITORINFOEX);
			GetMonitorInfo(hMonitor, &monitorInfoEx);

			//size_t devNameLen = strlen(monitorInfoEx.szDevice);
			//mDeviceName = new char[devNameLen + 1];

			//strcpy(mDeviceName, monitorInfoEx.szDevice);

			// No specified top left -> Center the window in the middle of the monitor
			if (left == -1 || top == -1)
			{
				int screenw = monitorInfoEx.rcMonitor.right  - monitorInfoEx.rcMonitor.left;
				int screenh = monitorInfoEx.rcMonitor.bottom - monitorInfoEx.rcMonitor.top;

				SetRect(&rc, 0, 0, width, height);
				AdjustWindowRect(&rc, dwStyle, false);

				// clamp window dimensions to screen size
				int outerw = (rc.right-rc.left < screenw)? rc.right-rc.left : screenw;
				int outerh = (rc.bottom-rc.top < screenh)? rc.bottom-rc.top : screenh;

				if (left == -1)
					left = monitorInfoEx.rcMonitor.left + (screenw - outerw) / 2;
				else if (monitorIndex != -1)
					left += monitorInfoEx.rcMonitor.left;

				if (top == -1)
					top = monitorInfoEx.rcMonitor.top + (screenh - outerh) / 2;
				else if (monitorIndex != -1)
					top += monitorInfoEx.rcMonitor.top;
			}
			else if (monitorIndex != -1)
			{
				left += monitorInfoEx.rcMonitor.left;
				top += monitorInfoEx.rcMonitor.top;
			}

			mWidth = width;
			mHeight = height;
			mTop = top;
			mLeft = left;

			if (mIsFullScreen)
			{
				dwStyle |= WS_POPUP;
				dwStyleEx |= WS_EX_TOPMOST;
				mTop = monitorInfoEx.rcMonitor.top;
				mLeft = monitorInfoEx.rcMonitor.left;
			}
			else
			{
				if (parent)
				{
					dwStyle |= WS_CHILD;
				}
				else
				{
					if (border == "none")
						dwStyle |= WS_POPUP;
					else if (border == "fixed")
						dwStyle |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION |
						WS_SYSMENU | WS_MINIMIZEBOX;
					else
						dwStyle |= WS_OVERLAPPEDWINDOW;
				}

				int screenw = GetSystemMetrics(SM_CXSCREEN);
				int screenh = GetSystemMetrics(SM_CYSCREEN);

				if (!outerSize)
				{
					// Calculate window dimensions required
					// to get the requested client area
					SetRect(&rc, 0, 0, mWidth, mHeight);
					AdjustWindowRect(&rc, dwStyle, false);
					mWidth = rc.right - rc.left;
					mHeight = rc.bottom - rc.top;

					// Clamp window rect to the nearest display monitor.
					if (mLeft < monitorInfoEx.rcMonitor.left)
						mLeft = monitorInfoEx.rcMonitor.left;

					if (mTop < monitorInfoEx.rcMonitor.top)
						mTop = monitorInfoEx.rcMonitor.top;

					if ((int)mWidth > monitorInfoEx.rcMonitor.right - mLeft)
						mWidth = monitorInfoEx.rcMonitor.right - mLeft;

					if ((int)mHeight > monitorInfoEx.rcMonitor.bottom - mTop)
						mHeight = monitorInfoEx.rcMonitor.bottom - mTop;
				}
			}

			// register class and create window
			WNDCLASS wc = { CS_OWNDC, WindowEventUtilities::_WndProc, 0, 0, hInst,
				LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
				(HBRUSH)GetStockObject(BLACK_BRUSH), NULL, "OgreGLWindow" };
			RegisterClass(&wc);

			if (mIsFullScreen)
			{
				DEVMODE displayDeviceMode;

				memset(&displayDeviceMode, 0, sizeof(displayDeviceMode));
				displayDeviceMode.dmSize = sizeof(DEVMODE);
				displayDeviceMode.dmBitsPerPel = mColourDepth;
				displayDeviceMode.dmPelsWidth = mWidth;
				displayDeviceMode.dmPelsHeight = mHeight;
				displayDeviceMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
/*
				if (mDisplayFrequency)
				{
					displayDeviceMode.dmDisplayFrequency = mDisplayFrequency;
					displayDeviceMode.dmFields |= DM_DISPLAYFREQUENCY;
					if (ChangeDisplaySettingsEx(mDeviceName, &displayDeviceMode, NULL, CDS_FULLSCREEN | CDS_TEST, NULL) != DISP_CHANGE_SUCCESSFUL)
					{
						LogManager::getSingleton().logMessage(LML_NORMAL, "ChangeDisplaySettings with user display frequency failed");
						displayDeviceMode.dmFields ^= DM_DISPLAYFREQUENCY;
					}
				}
				if (ChangeDisplaySettingsEx(mDeviceName, &displayDeviceMode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
					LogManager::getSingleton().logMessage(LML_CRITICAL, "ChangeDisplaySettings failed");
*/

			}
			// Pass pointer to self as WM_CREATE parameter
			mWindow = CreateWindowEx(dwStyleEx, "OgreGLWindow", title.c_str(),
				dwStyle, mLeft, mTop, mWidth, mHeight, parent, 0, hInst, this);

			WindowEventUtilities::_addRenderWindow(this);

			LogManager::getSingleton().stream()
				<< "Created Win32Window '"
				<< mName << "' : " << mWidth << "x" << mHeight
				<< ", " << mColourDepth << "bpp";

		}

		RECT rc;
		// top and left represent outer window position
		GetWindowRect(mWindow, &rc);
		mTop = rc.top;
		mLeft = rc.left;
		// width and height represent drawable area only
		GetClientRect(mWindow, &rc);
		mWidth = rc.right;
		mHeight = rc.bottom;

		mNativeDisplay = GetDC(mWindow);
		mEglDisplay = eglGetDisplay(mNativeDisplay);
		mGLSupport->setGLDisplay(mEglDisplay);
		mEglSurface = createSurfaceFromWindow(mEglDisplay, mWindow);

	}

	void Win32EGLWindow::reposition( int left, int top )
	{

	}

	void Win32EGLWindow::resize( unsigned int width, unsigned int height )
	{

	}

	void Win32EGLWindow::windowMovedOrResized()
	{

	}

	void Win32EGLWindow::switchFullScreen( bool fullscreen )
	{

	}

    void Win32EGLWindow::create(const String& name, uint width, uint height,
                                bool fullScreen, const NameValuePairList *miscParams)
    {
        String title = name;
        uint samples = 0;
        int gamma;
        short frequency = 0;
        bool vsync = false;
        ::EGLContext eglContext = 0;
		int left = 0;
		int top  = 0;

		getLeftAndTopFromNativeWindow(left, top, width, height);

        mIsFullScreen = fullScreen;

        if (miscParams)
        {
            NameValuePairList::const_iterator opt;
            NameValuePairList::const_iterator end = miscParams->end();

            if ((opt = miscParams->find("currentGLContext")) != end &&
                StringConverter::parseBool(opt->second))
            {
                eglContext = eglGetCurrentContext();
                if (eglContext)
                {
                    OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                                "currentGLContext was specified with no current GL context",
                                "EGLWindow::create");
                }

                eglContext = eglGetCurrentContext();
                mEglSurface = eglGetCurrentSurface(EGL_DRAW);
            }

            // Note: Some platforms support AA inside ordinary windows
            if ((opt = miscParams->find("FSAA")) != end)
            {
                samples = StringConverter::parseUnsignedInt(opt->second);
            }

            if ((opt = miscParams->find("displayFrequency")) != end)
            {
                frequency = (short)StringConverter::parseInt(opt->second);
            }

            if ((opt = miscParams->find("vsync")) != end)
            {
                vsync = StringConverter::parseBool(opt->second);
            }

            if ((opt = miscParams->find("gamma")) != end)
            {
                gamma = StringConverter::parseBool(opt->second);
            }

            if ((opt = miscParams->find("left")) != end)
            {
                left = StringConverter::parseInt(opt->second);
            }

            if ((opt = miscParams->find("top")) != end)
            {
                top = StringConverter::parseInt(opt->second);
            }

            if ((opt = miscParams->find("title")) != end)
            {
                title = opt->second;
            }

            if ((opt = miscParams->find("externalGLControl")) != end)
            {
                mIsExternalGLControl = StringConverter::parseBool(opt->second);
            }
		}

		initNativeCreatedWindow(miscParams);

        if (mEglSurface)
        {
            mEglConfig = mGLSupport->getGLConfigFromDrawable (mEglSurface, &width, &height);
        }

        if (!mEglConfig && eglContext)
        {
            mEglConfig = mGLSupport->getGLConfigFromContext(eglContext);

            if (!mEglConfig)
            {
                // This should never happen.
                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                            "Unexpected failure to determine a EGLFBConfig",
                            "EGLWindow::create");
            }
        }

        mIsExternal = (mEglSurface != 0);

        if (!mEglConfig)
        {
            int minAttribs[] = {
                EGL_LEVEL, 0,
                EGL_DEPTH_SIZE, 16,
                EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
                EGL_NONE
            };

            int maxAttribs[] = {
                EGL_SAMPLES, samples,
                EGL_STENCIL_SIZE, INT_MAX,
                EGL_NONE
            };

            mEglConfig = mGLSupport->selectGLConfig(minAttribs, maxAttribs);
            mHwGamma = false;
        }

        if (!mIsTopLevel)
        {
            mIsFullScreen = false;
            left = top = 0;
        }

        if (mIsFullScreen)
        {
            mGLSupport->switchMode (width, height, frequency);
        }

		if (!mIsExternal)
        {
			createNativeWindow(left, top, width, height, title);
		}

		mContext = createEGLContext();

        ::EGLSurface oldDrawableDraw = eglGetCurrentSurface(EGL_DRAW);
        ::EGLSurface oldDrawableRead = eglGetCurrentSurface(EGL_READ);
        ::EGLContext oldContext  = eglGetCurrentContext();

        int glConfigID;

        mGLSupport->getGLConfigAttrib(mEglConfig, EGL_CONFIG_ID, &glConfigID);
        LogManager::getSingleton().logMessage("EGLWindow::create used FBConfigID = " + StringConverter::toString(glConfigID));

        mName = name;
        mWidth = width;
        mHeight = height;
        mLeft = left;
        mTop = top;
        mActive = true;
		mVisible = true;

        mClosed = false;
	}

}
<commit_msg>GLES: Remove obselete data member initialization<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2008 Renato Araujo Oliveira Filho <renatox@gmail.com>
Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
--------------------------------------------------------------------------*/

#include "OgreRoot.h"
#include "OgreException.h"
#include "OgreLogManager.h"
#include "OgreStringConverter.h"
#include "OgreWindowEventUtilities.h"

#include "OgreGLESPrerequisites.h"
#include "OgreGLESRenderSystem.h"

#include "OgreWin32EGLSupport.h"
#include "OgreWin32EGLWindow.h"
#include "OgreWin32EGLContext.h"

#include <iostream>
#include <algorithm>
#include <climits>

namespace Ogre {
    Win32EGLWindow::Win32EGLWindow(Win32EGLSupport *glsupport)
		: EGLWindow(glsupport)
    {
		mGLSupport = glsupport;
		mNativeDisplay = glsupport->getNativeDisplay();
    }

    Win32EGLWindow::~Win32EGLWindow()
    {
    }

	EGLContext * Win32EGLWindow::createEGLContext() const
	{
		return new Win32EGLContext(mEglDisplay, mGLSupport, mEglConfig, mEglSurface);
	}

	void Win32EGLWindow::getLeftAndTopFromNativeWindow( int & left, int & top, uint width, uint height )
	{

	}

	void Win32EGLWindow::initNativeCreatedWindow(const NameValuePairList *miscParams)
	{

	}

	void Win32EGLWindow::createNativeWindow( int &left, int &top, uint &width, uint &height, String &title )
	{
		// destroy current window, if any
		if (mWindow)
			destroy();

#ifdef OGRE_STATIC_LIB
		HINSTANCE hInst = GetModuleHandle( NULL );
#else
#  if OGRE_DEBUG_MODE == 1
		HINSTANCE hInst = GetModuleHandle("RenderSystem_GLES_d.dll");
#  else
		HINSTANCE hInst = GetModuleHandle("RenderSystem_GLES.dll");
#  endif
#endif

		mWindow = 0;
		mClosed = false;
		mColourDepth = mIsFullScreen? 32 : GetDeviceCaps(GetDC(0), BITSPIXEL);
		HWND parent = 0;
		bool vsync = false;
		String border;
		bool outerSize = false;
		bool hwGamma = false;
		int monitorIndex = -1;
		HMONITOR hMonitor = NULL;

		if (!mIsExternal)
		{
			DWORD		  dwStyle = WS_VISIBLE | WS_CLIPCHILDREN;
			DWORD		  dwStyleEx = 0;
			MONITORINFOEX monitorInfoEx;
			RECT		  rc;

			// If we didn't specified the adapter index, or if it didn't find it
			if (hMonitor == NULL)
			{
				POINT windowAnchorPoint;

				// Fill in anchor point.
				windowAnchorPoint.x = left;
				windowAnchorPoint.y = top;

				// Get the nearest monitor to this window.
				hMonitor = MonitorFromPoint(windowAnchorPoint, MONITOR_DEFAULTTONEAREST);
			}

			// Get the target monitor info
			memset(&monitorInfoEx, 0, sizeof(MONITORINFOEX));
			monitorInfoEx.cbSize = sizeof(MONITORINFOEX);
			GetMonitorInfo(hMonitor, &monitorInfoEx);

			//size_t devNameLen = strlen(monitorInfoEx.szDevice);
			//mDeviceName = new char[devNameLen + 1];

			//strcpy(mDeviceName, monitorInfoEx.szDevice);

			// No specified top left -> Center the window in the middle of the monitor
			if (left == -1 || top == -1)
			{
				int screenw = monitorInfoEx.rcMonitor.right  - monitorInfoEx.rcMonitor.left;
				int screenh = monitorInfoEx.rcMonitor.bottom - monitorInfoEx.rcMonitor.top;

				SetRect(&rc, 0, 0, width, height);
				AdjustWindowRect(&rc, dwStyle, false);

				// clamp window dimensions to screen size
				int outerw = (rc.right-rc.left < screenw)? rc.right-rc.left : screenw;
				int outerh = (rc.bottom-rc.top < screenh)? rc.bottom-rc.top : screenh;

				if (left == -1)
					left = monitorInfoEx.rcMonitor.left + (screenw - outerw) / 2;
				else if (monitorIndex != -1)
					left += monitorInfoEx.rcMonitor.left;

				if (top == -1)
					top = monitorInfoEx.rcMonitor.top + (screenh - outerh) / 2;
				else if (monitorIndex != -1)
					top += monitorInfoEx.rcMonitor.top;
			}
			else if (monitorIndex != -1)
			{
				left += monitorInfoEx.rcMonitor.left;
				top += monitorInfoEx.rcMonitor.top;
			}

			mWidth = width;
			mHeight = height;
			mTop = top;
			mLeft = left;

			if (mIsFullScreen)
			{
				dwStyle |= WS_POPUP;
				dwStyleEx |= WS_EX_TOPMOST;
				mTop = monitorInfoEx.rcMonitor.top;
				mLeft = monitorInfoEx.rcMonitor.left;
			}
			else
			{
				if (parent)
				{
					dwStyle |= WS_CHILD;
				}
				else
				{
					if (border == "none")
						dwStyle |= WS_POPUP;
					else if (border == "fixed")
						dwStyle |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION |
						WS_SYSMENU | WS_MINIMIZEBOX;
					else
						dwStyle |= WS_OVERLAPPEDWINDOW;
				}

				int screenw = GetSystemMetrics(SM_CXSCREEN);
				int screenh = GetSystemMetrics(SM_CYSCREEN);

				if (!outerSize)
				{
					// Calculate window dimensions required
					// to get the requested client area
					SetRect(&rc, 0, 0, mWidth, mHeight);
					AdjustWindowRect(&rc, dwStyle, false);
					mWidth = rc.right - rc.left;
					mHeight = rc.bottom - rc.top;

					// Clamp window rect to the nearest display monitor.
					if (mLeft < monitorInfoEx.rcMonitor.left)
						mLeft = monitorInfoEx.rcMonitor.left;

					if (mTop < monitorInfoEx.rcMonitor.top)
						mTop = monitorInfoEx.rcMonitor.top;

					if ((int)mWidth > monitorInfoEx.rcMonitor.right - mLeft)
						mWidth = monitorInfoEx.rcMonitor.right - mLeft;

					if ((int)mHeight > monitorInfoEx.rcMonitor.bottom - mTop)
						mHeight = monitorInfoEx.rcMonitor.bottom - mTop;
				}
			}

			// register class and create window
			WNDCLASS wc = { CS_OWNDC, WindowEventUtilities::_WndProc, 0, 0, hInst,
				LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
				(HBRUSH)GetStockObject(BLACK_BRUSH), NULL, "OgreGLWindow" };
			RegisterClass(&wc);

			if (mIsFullScreen)
			{
				DEVMODE displayDeviceMode;

				memset(&displayDeviceMode, 0, sizeof(displayDeviceMode));
				displayDeviceMode.dmSize = sizeof(DEVMODE);
				displayDeviceMode.dmBitsPerPel = mColourDepth;
				displayDeviceMode.dmPelsWidth = mWidth;
				displayDeviceMode.dmPelsHeight = mHeight;
				displayDeviceMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
/*
				if (mDisplayFrequency)
				{
					displayDeviceMode.dmDisplayFrequency = mDisplayFrequency;
					displayDeviceMode.dmFields |= DM_DISPLAYFREQUENCY;
					if (ChangeDisplaySettingsEx(mDeviceName, &displayDeviceMode, NULL, CDS_FULLSCREEN | CDS_TEST, NULL) != DISP_CHANGE_SUCCESSFUL)
					{
						LogManager::getSingleton().logMessage(LML_NORMAL, "ChangeDisplaySettings with user display frequency failed");
						displayDeviceMode.dmFields ^= DM_DISPLAYFREQUENCY;
					}
				}
				if (ChangeDisplaySettingsEx(mDeviceName, &displayDeviceMode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
					LogManager::getSingleton().logMessage(LML_CRITICAL, "ChangeDisplaySettings failed");
*/

			}
			// Pass pointer to self as WM_CREATE parameter
			mWindow = CreateWindowEx(dwStyleEx, "OgreGLWindow", title.c_str(),
				dwStyle, mLeft, mTop, mWidth, mHeight, parent, 0, hInst, this);

			WindowEventUtilities::_addRenderWindow(this);

			LogManager::getSingleton().stream()
				<< "Created Win32Window '"
				<< mName << "' : " << mWidth << "x" << mHeight
				<< ", " << mColourDepth << "bpp";

		}

		RECT rc;
		// top and left represent outer window position
		GetWindowRect(mWindow, &rc);
		mTop = rc.top;
		mLeft = rc.left;
		// width and height represent drawable area only
		GetClientRect(mWindow, &rc);
		mWidth = rc.right;
		mHeight = rc.bottom;

		mNativeDisplay = GetDC(mWindow);
		mEglDisplay = eglGetDisplay(mNativeDisplay);
		mGLSupport->setGLDisplay(mEglDisplay);
		mEglSurface = createSurfaceFromWindow(mEglDisplay, mWindow);

	}

	void Win32EGLWindow::reposition( int left, int top )
	{

	}

	void Win32EGLWindow::resize( unsigned int width, unsigned int height )
	{

	}

	void Win32EGLWindow::windowMovedOrResized()
	{

	}

	void Win32EGLWindow::switchFullScreen( bool fullscreen )
	{

	}

    void Win32EGLWindow::create(const String& name, uint width, uint height,
                                bool fullScreen, const NameValuePairList *miscParams)
    {
        String title = name;
        uint samples = 0;
        int gamma;
        short frequency = 0;
        bool vsync = false;
        ::EGLContext eglContext = 0;
		int left = 0;
		int top  = 0;

		getLeftAndTopFromNativeWindow(left, top, width, height);

        mIsFullScreen = fullScreen;

        if (miscParams)
        {
            NameValuePairList::const_iterator opt;
            NameValuePairList::const_iterator end = miscParams->end();

            if ((opt = miscParams->find("currentGLContext")) != end &&
                StringConverter::parseBool(opt->second))
            {
                eglContext = eglGetCurrentContext();
                if (eglContext)
                {
                    OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                                "currentGLContext was specified with no current GL context",
                                "EGLWindow::create");
                }

                eglContext = eglGetCurrentContext();
                mEglSurface = eglGetCurrentSurface(EGL_DRAW);
            }

            // Note: Some platforms support AA inside ordinary windows
            if ((opt = miscParams->find("FSAA")) != end)
            {
                samples = StringConverter::parseUnsignedInt(opt->second);
            }

            if ((opt = miscParams->find("displayFrequency")) != end)
            {
                frequency = (short)StringConverter::parseInt(opt->second);
            }

            if ((opt = miscParams->find("vsync")) != end)
            {
                vsync = StringConverter::parseBool(opt->second);
            }

            if ((opt = miscParams->find("gamma")) != end)
            {
                gamma = StringConverter::parseBool(opt->second);
            }

            if ((opt = miscParams->find("left")) != end)
            {
                left = StringConverter::parseInt(opt->second);
            }

            if ((opt = miscParams->find("top")) != end)
            {
                top = StringConverter::parseInt(opt->second);
            }

            if ((opt = miscParams->find("title")) != end)
            {
                title = opt->second;
            }

            if ((opt = miscParams->find("externalGLControl")) != end)
            {
                mIsExternalGLControl = StringConverter::parseBool(opt->second);
            }
		}

		initNativeCreatedWindow(miscParams);

        if (mEglSurface)
        {
            mEglConfig = mGLSupport->getGLConfigFromDrawable (mEglSurface, &width, &height);
        }

        if (!mEglConfig && eglContext)
        {
            mEglConfig = mGLSupport->getGLConfigFromContext(eglContext);

            if (!mEglConfig)
            {
                // This should never happen.
                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                            "Unexpected failure to determine a EGLFBConfig",
                            "EGLWindow::create");
            }
        }

        mIsExternal = (mEglSurface != 0);

        if (!mEglConfig)
        {
            int minAttribs[] = {
                EGL_LEVEL, 0,
                EGL_DEPTH_SIZE, 16,
                EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
                EGL_NONE
            };

            int maxAttribs[] = {
                EGL_SAMPLES, samples,
                EGL_STENCIL_SIZE, INT_MAX,
                EGL_NONE
            };

            mEglConfig = mGLSupport->selectGLConfig(minAttribs, maxAttribs);
            mHwGamma = false;
        }

        if (!mIsTopLevel)
        {
            mIsFullScreen = false;
            left = top = 0;
        }

        if (mIsFullScreen)
        {
            mGLSupport->switchMode (width, height, frequency);
        }

		if (!mIsExternal)
        {
			createNativeWindow(left, top, width, height, title);
		}

		mContext = createEGLContext();

        ::EGLSurface oldDrawableDraw = eglGetCurrentSurface(EGL_DRAW);
        ::EGLSurface oldDrawableRead = eglGetCurrentSurface(EGL_READ);
        ::EGLContext oldContext  = eglGetCurrentContext();

        int glConfigID;

        mGLSupport->getGLConfigAttrib(mEglConfig, EGL_CONFIG_ID, &glConfigID);
        LogManager::getSingleton().logMessage("EGLWindow::create used FBConfigID = " + StringConverter::toString(glConfigID));

        mName = name;
        mWidth = width;
        mHeight = height;
        mLeft = left;
        mTop = top;
        mActive = true;
		mVisible = true;

        mClosed = false;
	}

}
<|endoftext|>


<commit_before>//
//  PCMSegment.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 17/12/2016.
//  Copyright 2016 Thomas Harte. All rights reserved.
//

#include "PCMSegment.hpp"

#include <cassert>
#include <cstdlib>

using namespace Storage::Disk;

PCMSegmentEventSource::PCMSegmentEventSource(const PCMSegment &segment) :
		segment_(new PCMSegment(segment)) {
	// add an extra bit of storage at the bottom if one is going to be needed;
	// events returned are going to be in integral multiples of the length of a bit
	// other than the very first and very last which will include a half bit length
	if(segment_->length_of_a_bit.length&1) {
		segment_->length_of_a_bit.length <<= 1;
		segment_->length_of_a_bit.clock_rate <<= 1;
	}

	// load up the clock rate once only
	next_event_.length.clock_rate = segment_->length_of_a_bit.clock_rate;

	// set initial conditions
	reset();
}

PCMSegmentEventSource::PCMSegmentEventSource(const PCMSegmentEventSource &original) {
	// share underlying data with the original
	segment_ = original.segment_;

	// load up the clock rate and set initial conditions
	next_event_.length.clock_rate = segment_->length_of_a_bit.clock_rate;
	reset();
}

void PCMSegmentEventSource::reset() {
	// start with the first bit to be considered the zeroth, and assume that it'll be
	// flux transitions for the foreseeable
	bit_pointer_ = 0;
	next_event_.type = Track::Event::FluxTransition;
}

PCMSegment &PCMSegment::operator +=(const PCMSegment &rhs) {
	data.insert(data.end(), rhs.data.begin(), rhs.data.end());
	return *this;
}

void PCMSegment::rotate_right(size_t length) {
	length %= data.size();
	if(!length) return;

	// To rotate to the right, front-insert the proper number
	// of bits from the end and then resize. To rotate to
	// the left, do the opposite.
	std::vector<uint8_t> data_copy;
	if(length > 0) {
		data_copy.insert(data_copy.end(), data.end() - off_t(length), data.end());
		data.erase(data.end() - off_t(length), data.end());
		data.insert(data.begin(), data_copy.begin(), data_copy.end());
	} else {
		data_copy.insert(data_copy.end(), data.begin(), data.begin() - off_t(length));
		data.erase(data.begin(), data.begin() - off_t(length));
		data.insert(data.end(), data_copy.begin(), data_copy.end());
	}
}

Storage::Disk::Track::Event PCMSegmentEventSource::get_next_event() {
	// Track the initial bit pointer for potentially considering whether this was an
	// initial index hole or a subsequent one later on.
	const std::size_t initial_bit_pointer = bit_pointer_;

	// If starting from the beginning, pull half a bit backward, as if the initial bit
	// is set, it should be in the centre of its window.
	next_event_.length.length = bit_pointer_ ? 0 : -(segment_->length_of_a_bit.length >> 1);

	// search for the next bit that is set, if any
	while(bit_pointer_ < segment_->data.size()) {
		bool bit = segment_->data[bit_pointer_];
		++bit_pointer_;	// so this always points one beyond the most recent bit returned
		next_event_.length.length += segment_->length_of_a_bit.length;

		// if this bit is set, or is fuzzy and a random bit of 1 is selected, return the event.
		if(bit ||
			(!segment_->fuzzy_mask.empty() && segment_->fuzzy_mask[bit_pointer_] && lfsr_.next())
		)	return next_event_;
	}

	// If the end is reached without a bit being set, it'll be index holes from now on.
	next_event_.type = Track::Event::IndexHole;

	// Test whether this is the very first time that bits have been exhausted. If so then
	// allow an extra half bit's length to run from the position of the potential final transition
	// event to the end of the segment. Otherwise don't allow any extra time, as it's already
	// been consumed.
	if(initial_bit_pointer <= segment_->data.size()) {
		next_event_.length.length += (segment_->length_of_a_bit.length >> 1);
		bit_pointer_++;
	}
	return next_event_;
}

Storage::Time PCMSegmentEventSource::get_length() {
	return segment_->length_of_a_bit * unsigned(segment_->data.size());
}

float PCMSegmentEventSource::seek_to(float time_from_start) {
	// test for requested time being beyond the end
	const float length = get_length().get<float>();
	if(time_from_start >= length) {
		next_event_.type = Track::Event::IndexHole;
		bit_pointer_ = segment_->data.size()+1;
		return length;
	}

	// if not beyond the end then make an initial assumption that the next thing encountered will be a flux transition
	next_event_.type = Track::Event::FluxTransition;

	// test for requested time being before the first bit
	const float bit_length = segment_->length_of_a_bit.get<float>();
	const float half_bit_length = bit_length / 2.0f;
	if(time_from_start < half_bit_length) {
		bit_pointer_ = 0;
		return 0.0f;
	}

	// adjust for time to get to bit zero and determine number of bits in;
	// bit_pointer_ always records _the next bit_ that might trigger an event,
	// so should be one beyond the one reached by a seek.
	const float relative_time = time_from_start + half_bit_length;	// the period [0, 0.5) should map to window 0; [0.5, 1.5) should map to window 1; etc.
	bit_pointer_ = 1 + size_t(relative_time / bit_length);

	// map up to the correct amount of time
	return half_bit_length + segment_->length_of_a_bit.get<float>() * float(bit_pointer_ - 1);
}

const PCMSegment &PCMSegmentEventSource::segment() const {
	return *segment_;
}

PCMSegment &PCMSegmentEventSource::segment() {
	return *segment_;
}
<commit_msg>Simplifies calculations very slightly.<commit_after>//
//  PCMSegment.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 17/12/2016.
//  Copyright 2016 Thomas Harte. All rights reserved.
//

#include "PCMSegment.hpp"

#include <cassert>
#include <cstdlib>

using namespace Storage::Disk;

PCMSegmentEventSource::PCMSegmentEventSource(const PCMSegment &segment) :
		segment_(new PCMSegment(segment)) {
	// add an extra bit of storage at the bottom if one is going to be needed;
	// events returned are going to be in integral multiples of the length of a bit
	// other than the very first and very last which will include a half bit length
	if(segment_->length_of_a_bit.length&1) {
		segment_->length_of_a_bit.length <<= 1;
		segment_->length_of_a_bit.clock_rate <<= 1;
	}

	// load up the clock rate once only
	next_event_.length.clock_rate = segment_->length_of_a_bit.clock_rate;

	// set initial conditions
	reset();
}

PCMSegmentEventSource::PCMSegmentEventSource(const PCMSegmentEventSource &original) {
	// share underlying data with the original
	segment_ = original.segment_;

	// load up the clock rate and set initial conditions
	next_event_.length.clock_rate = segment_->length_of_a_bit.clock_rate;
	reset();
}

void PCMSegmentEventSource::reset() {
	// start with the first bit to be considered the zeroth, and assume that it'll be
	// flux transitions for the foreseeable
	bit_pointer_ = 0;
	next_event_.type = Track::Event::FluxTransition;
}

PCMSegment &PCMSegment::operator +=(const PCMSegment &rhs) {
	data.insert(data.end(), rhs.data.begin(), rhs.data.end());
	return *this;
}

void PCMSegment::rotate_right(size_t length) {
	length %= data.size();
	if(!length) return;

	// To rotate to the right, front-insert the proper number
	// of bits from the end and then resize. To rotate to
	// the left, do the opposite.
	std::vector<uint8_t> data_copy;
	if(length > 0) {
		data_copy.insert(data_copy.end(), data.end() - off_t(length), data.end());
		data.erase(data.end() - off_t(length), data.end());
		data.insert(data.begin(), data_copy.begin(), data_copy.end());
	} else {
		data_copy.insert(data_copy.end(), data.begin(), data.begin() - off_t(length));
		data.erase(data.begin(), data.begin() - off_t(length));
		data.insert(data.end(), data_copy.begin(), data_copy.end());
	}
}

Storage::Disk::Track::Event PCMSegmentEventSource::get_next_event() {
	// Track the initial bit pointer for potentially considering whether this was an
	// initial index hole or a subsequent one later on.
	const std::size_t initial_bit_pointer = bit_pointer_;

	// If starting from the beginning, pull half a bit backward, as if the initial bit
	// is set, it should be in the centre of its window.
	next_event_.length.length = bit_pointer_ ? 0 : -(segment_->length_of_a_bit.length >> 1);

	// search for the next bit that is set, if any
	while(bit_pointer_ < segment_->data.size()) {
		bool bit = segment_->data[bit_pointer_];
		++bit_pointer_;	// so this always points one beyond the most recent bit returned
		next_event_.length.length += segment_->length_of_a_bit.length;

		// if this bit is set, or is fuzzy and a random bit of 1 is selected, return the event.
		if(bit ||
			(!segment_->fuzzy_mask.empty() && segment_->fuzzy_mask[bit_pointer_] && lfsr_.next())
		)	return next_event_;
	}

	// If the end is reached without a bit being set, it'll be index holes from now on.
	next_event_.type = Track::Event::IndexHole;

	// Test whether this is the very first time that bits have been exhausted. If so then
	// allow an extra half bit's length to run from the position of the potential final transition
	// event to the end of the segment. Otherwise don't allow any extra time, as it's already
	// been consumed.
	if(initial_bit_pointer <= segment_->data.size()) {
		next_event_.length.length += (segment_->length_of_a_bit.length >> 1);
		bit_pointer_++;
	}
	return next_event_;
}

Storage::Time PCMSegmentEventSource::get_length() {
	return segment_->length_of_a_bit * unsigned(segment_->data.size());
}

float PCMSegmentEventSource::seek_to(float time_from_start) {
	// test for requested time being beyond the end
	const float length = get_length().get<float>();
	if(time_from_start >= length) {
		next_event_.type = Track::Event::IndexHole;
		bit_pointer_ = segment_->data.size()+1;
		return length;
	}

	// if not beyond the end then make an initial assumption that the next thing encountered will be a flux transition
	next_event_.type = Track::Event::FluxTransition;

	// test for requested time being before the first bit
	const float bit_length = segment_->length_of_a_bit.get<float>();
	const float half_bit_length = bit_length / 2.0f;
	if(time_from_start < half_bit_length) {
		bit_pointer_ = 0;
		return 0.0f;
	}

	// adjust for time to get to bit zero and determine number of bits in;
	// bit_pointer_ always records _the next bit_ that might trigger an event,
	// so should be one beyond the one reached by a seek.
	const float relative_time = time_from_start + half_bit_length;	// the period [0, 0.5) should map to window 0, ending with bit 0; [0.5, 1.5) should map to window 1; etc.
	bit_pointer_ = size_t(relative_time / bit_length);

	// Map up to the correct amount of time; this should be the start of the window that ends upon the bit at bit_pointer_.
	return bit_length * float(bit_pointer_) - half_bit_length;
}

const PCMSegment &PCMSegmentEventSource::segment() const {
	return *segment_;
}

PCMSegment &PCMSegmentEventSource::segment() {
	return *segment_;
}
<|endoftext|>


<commit_before>
#include "MultidropSlave.h"
#include <util/crc16.h>

#define SOM 0xFF

MultidropSlave::MultidropSlave(MultidropData *_serial) : Multidrop(_serial) {
  flags = 0;
  myAddress = 0;
  responseHandler = 0;
  parseState = NO_MESSAGE;
}

uint8_t MultidropSlave::hasNewMessage() {
  return parseState == MESSAGE_READY;
}

uint8_t MultidropSlave::isAddressedToMe() {
  return hasNewMessage() && (address == myAddress || address == BROADCAST_ADDRESS);
}

uint8_t MultidropSlave::inBatchMode() {
  return flags & BATCH_FLAG;
}

uint8_t MultidropSlave::isResponseMessage() {
  return flags & RESPONSE_MESSAGE_FLAG;
}

uint8_t* MultidropSlave::getData() {
  return dataBuffer;
}

uint8_t MultidropSlave::getDataLen() {
  return dataIndex;
}

uint8_t MultidropSlave::getCommand() {
  return command;
}

void MultidropSlave::setAddress(uint8_t addr) {
  myAddress = addr;
}

void MultidropSlave::setResponseHandler(multidropResponseFunction handler) {
  responseHandler = handler;
}

void MultidropSlave::startMessage() {
  flags = 0;
  length = 0;
  address = 0;
  dataIndex = 0;
  dataBuffer[0] = '\0';
  fullDataLength = 0;
  fullDataIndex = 0;
  dataStartOffset = 0;

  messageCRC = ~0;
  messageCRC = _crc16_update(messageCRC, SOM);
  messageCRC = _crc16_update(messageCRC, SOM);
}

uint8_t MultidropSlave::read() {
  // Move onto the next message
  if (hasNewMessage()) {
    parseState = NO_MESSAGE;
  }

  while (serial->available()) {
    if(parse(serial->read()) == 1 && !isResponseMessage()) {
      return 1;
    }
  }
  return 0;
}

uint8_t MultidropSlave::parse(uint8_t b) {

  if (parseState == HEADER_SECTION) {
    parseHeader(b);
  }
  else if (parseState == DATA_SECTION) {
    processData(b);
  }
  // Validate CRC
  else if (parseState == END_SECTION) {
    uint8_t crcByte;

    if (parsePos == DATA_POS) { // First byte
      crcByte = (messageCRC >> 8) & 0xFF;
      parsePos = EOM1_POS;
    }
    else { // Second byte
      crcByte = messageCRC & 0xff;
      parsePos = EOM2_POS;
    }

    // Validate each byte
    if (crcByte != b) {
      parseState = NO_MESSAGE; // no match, abort
    }
    else if (parsePos == EOM2_POS) {
      parseState = MESSAGE_READY;
      return 1;
    }
  }
  else if (parseState == START_SECTION) {
    if (b == SOM) {
      startMessage();
      parsePos = SOM2_POS;
      parseState = HEADER_SECTION;
    }
    // No second 0xFF, so invalid start to message
    else {
      parseState = NO_MESSAGE;
    }
  }
  else if (parseState == NO_MESSAGE && b == SOM) {
    parsePos = SOM1_POS;
    parseState = START_SECTION;
  }

  return 0;
}

void MultidropSlave::parseHeader(uint8_t b) {
  messageCRC = _crc16_update(messageCRC, b);

  // Header flags
  if (parsePos == SOM2_POS) {
    parsePos = HEADER_FLAGS_POS;
    flags = b;
  }
  // Address
  else if (parsePos == HEADER_FLAGS_POS) {
    parsePos = HEADER_ADDR_POS;
    address = b;
  }
  // Command
  else if (parsePos == HEADER_ADDR_POS) {
    parsePos = HEADER_CMD_POS;
    command = b;
  }
  // Length, 1st byte
  else if (parsePos == HEADER_CMD_POS) {
    parsePos = HEADER_LEN1_POS;

    // in batch mode, the first length byte is the number of nodes
    if (inBatchMode()) {
      numNodes = b;
    } else {
      length = b;
      fullDataLength = b;
      dataStartOffset = 0;
      parseState = DATA_SECTION;
    }
  }
  // Length, 2nd byte (if in batch mode)
  else if (parsePos == HEADER_LEN1_POS) {
    length = b;
    fullDataLength = length * numNodes;
    dataStartOffset = (myAddress - 1) * length; // Where our data starts in the message

    parsePos = HEADER_LEN2_POS;
    parseState = DATA_SECTION;
  }

  // No data, continue to CRC
  if (parseState == DATA_SECTION && length == 0) {
    parseState = END_SECTION;
  }

  // If in response message, move straight to processData
  else if (parseState == DATA_SECTION && isResponseMessage() && myAddress == 0) {
    sendResponse();
  }
}

void MultidropSlave::processData(uint8_t b) {
  messageCRC = _crc16_update(messageCRC, b);
  parsePos = DATA_POS;

  // Provide a response to fill our data section
  if (isResponseMessage() && fullDataIndex == dataStartOffset) {
    sendResponse();
    return;
  }

  // If we're in our data section, fill data buffer
  else if (fullDataIndex >= dataStartOffset && dataIndex < length){
    dataBuffer[dataIndex++] = b;
    dataBuffer[dataIndex] = '\0';
  }
  // Done with data
  else if (fullDataIndex >= fullDataLength) {
    parseState = END_SECTION;
  }
  fullDataIndex++;
}

void MultidropSlave::sendResponse() {
  if (responseHandler) {
    uint8_t i;
    responseHandler(command, dataBuffer, length);
    for (i = 0; i < length; i++) {
      serial->write(dataBuffer[i]);
      fullDataIndex++;
    }
  }
}

<commit_msg>Fix bug in message processing.<commit_after>
#include "MultidropSlave.h"
#include <util/crc16.h>

#define SOM 0xFF

MultidropSlave::MultidropSlave(MultidropData *_serial) : Multidrop(_serial) {
  flags = 0;
  myAddress = 0;
  responseHandler = 0;
  parseState = NO_MESSAGE;
}

uint8_t MultidropSlave::hasNewMessage() {
  return parseState == MESSAGE_READY;
}

uint8_t MultidropSlave::isAddressedToMe() {
  return hasNewMessage() && (address == myAddress || address == BROADCAST_ADDRESS);
}

uint8_t MultidropSlave::inBatchMode() {
  return flags & BATCH_FLAG;
}

uint8_t MultidropSlave::isResponseMessage() {
  return flags & RESPONSE_MESSAGE_FLAG;
}

uint8_t* MultidropSlave::getData() {
  return dataBuffer;
}

uint8_t MultidropSlave::getDataLen() {
  return dataIndex;
}

uint8_t MultidropSlave::getCommand() {
  return command;
}

void MultidropSlave::setAddress(uint8_t addr) {
  myAddress = addr;
}

void MultidropSlave::setResponseHandler(multidropResponseFunction handler) {
  responseHandler = handler;
}

void MultidropSlave::startMessage() {
  flags = 0;
  length = 0;
  address = 0;
  dataIndex = 0;
  dataBuffer[0] = '\0';
  fullDataLength = 0;
  fullDataIndex = 0;
  dataStartOffset = 0;

  messageCRC = ~0;
  messageCRC = _crc16_update(messageCRC, SOM);
  messageCRC = _crc16_update(messageCRC, SOM);
}

uint8_t MultidropSlave::read() {
  // Move onto the next message
  if (parseState == MESSAGE_READY) {
    parseState = NO_MESSAGE;
  }

  while (serial->available()) {
    if(parse(serial->read()) == 1 && !isResponseMessage()) {
      return 1;
    }
  }
  return 0;
}

uint8_t MultidropSlave::parse(uint8_t b) {

  if (parseState == HEADER_SECTION) {
    parseHeader(b);
  }
  else if (parseState == DATA_SECTION) {
    processData(b);
  }
  // Validate CRC
  else if (parseState == END_SECTION) {
    uint8_t crcByte;

    if (parsePos == DATA_POS) { // First byte
      crcByte = (messageCRC >> 8) & 0xFF;
      parsePos = EOM1_POS;
    }
    else { // Second byte
      crcByte = messageCRC & 0xff;
      parsePos = EOM2_POS;
    }

    // Validate each byte
    if (crcByte != b) {
      parseState = NO_MESSAGE; // no match, abort
    }
    else if (parsePos == EOM2_POS) {
      parseState = MESSAGE_READY;
      return 1;
    }
  }
  // Second start byte
  else if (parseState == START_SECTION) {
    if (b == SOM) {
      startMessage();
      parsePos = SOM2_POS;
      parseState = HEADER_SECTION;
    }
    // No second 0xFF, so invalid start to message
    else {
      parseState = NO_MESSAGE;
    }
  }
  // First start byte
  else if (parseState == NO_MESSAGE && b == SOM) {
    parsePos = SOM1_POS;
    parseState = START_SECTION;
  }

  return 0;
}

void MultidropSlave::parseHeader(uint8_t b) {
  messageCRC = _crc16_update(messageCRC, b);

  // Header flags
  if (parsePos == SOM2_POS) {
    parsePos = HEADER_FLAGS_POS;
    flags = b;
  }
  // Address
  else if (parsePos == HEADER_FLAGS_POS) {
    parsePos = HEADER_ADDR_POS;
    address = b;
  }
  // Command
  else if (parsePos == HEADER_ADDR_POS) {
    parsePos = HEADER_CMD_POS;
    command = b;
  }
  // Length, 1st byte
  else if (parsePos == HEADER_CMD_POS) {
    parsePos = HEADER_LEN1_POS;

    // in batch mode, the first length byte is the number of nodes
    if (inBatchMode()) {
      numNodes = b;
    } else {
      length = b;
      fullDataLength = b;
      dataStartOffset = 0;
      parseState = DATA_SECTION;
    }
  }
  // Length, 2nd byte (if in batch mode)
  else if (parsePos == HEADER_LEN1_POS) {
    length = b;
    fullDataLength = length * numNodes;
    dataStartOffset = (myAddress - 1) * length; // Where our data starts in the message

    parsePos = HEADER_LEN2_POS;
    parseState = DATA_SECTION;
  }

  // No data, continue to CRC
  if (parseState == DATA_SECTION && length == 0) {
    parseState = END_SECTION;
  }

  // If in response message, move straight to processData
  else if (parseState == DATA_SECTION && isResponseMessage() && myAddress == 0) {
    sendResponse();
  }
}

void MultidropSlave::processData(uint8_t b) {
  messageCRC = _crc16_update(messageCRC, b);
  parsePos = DATA_POS;

  // Provide a response to fill our data section
  if (isResponseMessage() && fullDataIndex == dataStartOffset) {
    sendResponse();
    return;
  }

  // If we're in our data section, fill data buffer
  else if (fullDataIndex >= dataStartOffset && dataIndex < length){
    dataBuffer[dataIndex++] = b;
    dataBuffer[dataIndex] = '\0';
  }
  fullDataIndex++;

  // Done with data
  if (fullDataIndex >= fullDataLength) {
    parseState = END_SECTION;
  }
}

void MultidropSlave::sendResponse() {
  if (responseHandler) {
    uint8_t i;
    responseHandler(command, dataBuffer, length);
    for (i = 0; i < length; i++) {
      serial->write(dataBuffer[i]);
      messageCRC = _crc16_update(messageCRC, dataBuffer[i]);
      fullDataIndex++;
    }
  }
}

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "video/frame_encode_metadata_writer.h"

#include <algorithm>
#include <memory>
#include <utility>

#include "common_video/h264/sps_vui_rewriter.h"
#include "modules/include/module_common_types_public.h"
#include "modules/video_coding/include/video_coding_defines.h"
#include "rtc_base/logging.h"
#include "rtc_base/ref_counted_object.h"
#include "rtc_base/time_utils.h"

namespace webrtc {
namespace {
const int kMessagesThrottlingThreshold = 2;
const int kThrottleRatio = 100000;

class EncodedImageBufferWrapper : public EncodedImageBufferInterface {
 public:
  explicit EncodedImageBufferWrapper(rtc::Buffer&& buffer)
      : buffer_(std::move(buffer)) {}

  const uint8_t* data() const override { return buffer_.data(); }
  uint8_t* data() override { return buffer_.data(); }
  size_t size() const override { return buffer_.size(); }

 private:
  rtc::Buffer buffer_;
};

}  // namespace

FrameEncodeMetadataWriter::TimingFramesLayerInfo::TimingFramesLayerInfo() =
    default;
FrameEncodeMetadataWriter::TimingFramesLayerInfo::~TimingFramesLayerInfo() =
    default;

FrameEncodeMetadataWriter::FrameEncodeMetadataWriter(
    EncodedImageCallback* frame_drop_callback)
    : frame_drop_callback_(frame_drop_callback),
      internal_source_(false),
      framerate_fps_(0),
      last_timing_frame_time_ms_(-1),
      reordered_frames_logged_messages_(0),
      stalled_encoder_logged_messages_(0) {
  codec_settings_.timing_frame_thresholds = {-1, 0};
}
FrameEncodeMetadataWriter::~FrameEncodeMetadataWriter() {}

void FrameEncodeMetadataWriter::OnEncoderInit(const VideoCodec& codec,
                                              bool internal_source) {
  rtc::CritScope cs(&lock_);
  codec_settings_ = codec;
  internal_source_ = internal_source;
}

void FrameEncodeMetadataWriter::OnSetRates(
    const VideoBitrateAllocation& bitrate_allocation,
    uint32_t framerate_fps) {
  rtc::CritScope cs(&lock_);
  framerate_fps_ = framerate_fps;
  const size_t num_spatial_layers = NumSpatialLayers();
  if (timing_frames_info_.size() < num_spatial_layers) {
    timing_frames_info_.resize(num_spatial_layers);
  }
  for (size_t i = 0; i < num_spatial_layers; ++i) {
    timing_frames_info_[i].target_bitrate_bytes_per_sec =
        bitrate_allocation.GetSpatialLayerSum(i) / 8;
  }
}

void FrameEncodeMetadataWriter::OnEncodeStarted(const VideoFrame& frame) {
  rtc::CritScope cs(&lock_);
  if (internal_source_) {
    return;
  }

  const size_t num_spatial_layers = NumSpatialLayers();
  timing_frames_info_.resize(num_spatial_layers);
  FrameMetadata metadata;
  metadata.rtp_timestamp = frame.timestamp();
  metadata.encode_start_time_ms = rtc::TimeMillis();
  metadata.ntp_time_ms = frame.ntp_time_ms();
  metadata.timestamp_us = frame.timestamp_us();
  metadata.rotation = frame.rotation();
  metadata.color_space = frame.color_space();
  metadata.packet_infos = frame.packet_infos();
  for (size_t si = 0; si < num_spatial_layers; ++si) {
    RTC_DCHECK(timing_frames_info_[si].frames.empty() ||
               rtc::TimeDiff(
                   frame.render_time_ms(),
                   timing_frames_info_[si].frames.back().timestamp_us / 1000) >=
                   0);
    // If stream is disabled due to low bandwidth OnEncodeStarted still will be
    // called and have to be ignored.
    if (timing_frames_info_[si].target_bitrate_bytes_per_sec == 0)
      return;
    if (timing_frames_info_[si].frames.size() == kMaxEncodeStartTimeListSize) {
      ++stalled_encoder_logged_messages_;
      if (stalled_encoder_logged_messages_ <= kMessagesThrottlingThreshold ||
          stalled_encoder_logged_messages_ % kThrottleRatio == 0) {
        RTC_LOG(LS_WARNING) << "Too many frames in the encode_start_list."
                               " Did encoder stall?";
        if (stalled_encoder_logged_messages_ == kMessagesThrottlingThreshold) {
          RTC_LOG(LS_WARNING)
              << "Too many log messages. Further stalled encoder"
                 "warnings will be throttled.";
        }
      }
      frame_drop_callback_->OnDroppedFrame(
          EncodedImageCallback::DropReason::kDroppedByEncoder);
      timing_frames_info_[si].frames.pop_front();
    }
    timing_frames_info_[si].frames.emplace_back(metadata);
  }
}

void FrameEncodeMetadataWriter::FillTimingInfo(size_t simulcast_svc_idx,
                                               EncodedImage* encoded_image) {
  rtc::CritScope cs(&lock_);
  absl::optional<size_t> outlier_frame_size;
  absl::optional<int64_t> encode_start_ms;
  uint8_t timing_flags = VideoSendTiming::kNotTriggered;

  int64_t encode_done_ms = rtc::TimeMillis();

  // Encoders with internal sources do not call OnEncodeStarted
  // |timing_frames_info_| may be not filled here.
  if (!internal_source_) {
    encode_start_ms =
        ExtractEncodeStartTimeAndFillMetadata(simulcast_svc_idx, encoded_image);
  }

  if (timing_frames_info_.size() > simulcast_svc_idx) {
    size_t target_bitrate =
        timing_frames_info_[simulcast_svc_idx].target_bitrate_bytes_per_sec;
    if (framerate_fps_ > 0 && target_bitrate > 0) {
      // framerate and target bitrate were reported by encoder.
      size_t average_frame_size = target_bitrate / framerate_fps_;
      outlier_frame_size.emplace(
          average_frame_size *
          codec_settings_.timing_frame_thresholds.outlier_ratio_percent / 100);
    }
  }

  // Outliers trigger timing frames, but do not affect scheduled timing
  // frames.
  if (outlier_frame_size && encoded_image->size() >= *outlier_frame_size) {
    timing_flags |= VideoSendTiming::kTriggeredBySize;
  }

  // Check if it's time to send a timing frame.
  int64_t timing_frame_delay_ms =
      encoded_image->capture_time_ms_ - last_timing_frame_time_ms_;
  // Trigger threshold if it's a first frame, too long passed since the last
  // timing frame, or we already sent timing frame on a different simulcast
  // stream with the same capture time.
  if (last_timing_frame_time_ms_ == -1 ||
      timing_frame_delay_ms >=
          codec_settings_.timing_frame_thresholds.delay_ms ||
      timing_frame_delay_ms == 0) {
    timing_flags |= VideoSendTiming::kTriggeredByTimer;
    last_timing_frame_time_ms_ = encoded_image->capture_time_ms_;
  }

  // Workaround for chromoting encoder: it passes encode start and finished
  // timestamps in |timing_| field, but they (together with capture timestamp)
  // are not in the WebRTC clock.
  if (internal_source_ && encoded_image->timing_.encode_finish_ms > 0 &&
      encoded_image->timing_.encode_start_ms > 0) {
    int64_t clock_offset_ms =
        encode_done_ms - encoded_image->timing_.encode_finish_ms;
    // Translate capture timestamp to local WebRTC clock.
    encoded_image->capture_time_ms_ += clock_offset_ms;
    encoded_image->SetTimestamp(
        static_cast<uint32_t>(encoded_image->capture_time_ms_ * 90));
    encode_start_ms.emplace(encoded_image->timing_.encode_start_ms +
                            clock_offset_ms);
  }

  // If encode start is not available that means that encoder uses internal
  // source. In that case capture timestamp may be from a different clock with a
  // drift relative to rtc::TimeMillis(). We can't use it for Timing frames,
  // because to being sent in the network capture time required to be less than
  // all the other timestamps.
  if (encode_start_ms) {
    encoded_image->SetEncodeTime(*encode_start_ms, encode_done_ms);
    encoded_image->timing_.flags = timing_flags;
  } else {
    encoded_image->timing_.flags = VideoSendTiming::kInvalid;
  }
}

std::unique_ptr<RTPFragmentationHeader>
FrameEncodeMetadataWriter::UpdateBitstream(
    const CodecSpecificInfo* codec_specific_info,
    const RTPFragmentationHeader* fragmentation,
    EncodedImage* encoded_image) {
  if (!codec_specific_info ||
      codec_specific_info->codecType != kVideoCodecH264 || !fragmentation ||
      encoded_image->_frameType != VideoFrameType::kVideoFrameKey) {
    return nullptr;
  }

  rtc::Buffer modified_buffer;
  std::unique_ptr<RTPFragmentationHeader> modified_fragmentation =
      std::make_unique<RTPFragmentationHeader>();
  modified_fragmentation->CopyFrom(*fragmentation);

  // Make sure that the data is not copied if owned by EncodedImage.
  const EncodedImage& buffer = *encoded_image;
  SpsVuiRewriter::ParseOutgoingBitstreamAndRewriteSps(
      buffer, fragmentation->fragmentationVectorSize,
      fragmentation->fragmentationOffset, fragmentation->fragmentationLength,
      encoded_image->ColorSpace(), &modified_buffer,
      modified_fragmentation->fragmentationOffset,
      modified_fragmentation->fragmentationLength);

  encoded_image->SetEncodedData(
      new rtc::RefCountedObject<EncodedImageBufferWrapper>(
          std::move(modified_buffer)));

  return modified_fragmentation;
}

void FrameEncodeMetadataWriter::Reset() {
  rtc::CritScope cs(&lock_);
  for (auto& info : timing_frames_info_) {
    info.frames.clear();
  }
  last_timing_frame_time_ms_ = -1;
  reordered_frames_logged_messages_ = 0;
  stalled_encoder_logged_messages_ = 0;
}

absl::optional<int64_t>
FrameEncodeMetadataWriter::ExtractEncodeStartTimeAndFillMetadata(
    size_t simulcast_svc_idx,
    EncodedImage* encoded_image) {
  absl::optional<int64_t> result;
  size_t num_simulcast_svc_streams = timing_frames_info_.size();
  if (simulcast_svc_idx < num_simulcast_svc_streams) {
    auto metadata_list = &timing_frames_info_[simulcast_svc_idx].frames;
    // Skip frames for which there was OnEncodeStarted but no OnEncodedImage
    // call. These are dropped by encoder internally.
    // Because some hardware encoders don't preserve capture timestamp we
    // use RTP timestamps here.
    while (!metadata_list->empty() &&
           IsNewerTimestamp(encoded_image->Timestamp(),
                            metadata_list->front().rtp_timestamp)) {
      frame_drop_callback_->OnDroppedFrame(
          EncodedImageCallback::DropReason::kDroppedByEncoder);
      metadata_list->pop_front();
    }

    encoded_image->content_type_ =
        (codec_settings_.mode == VideoCodecMode::kScreensharing)
            ? VideoContentType::SCREENSHARE
            : VideoContentType::UNSPECIFIED;

    if (!metadata_list->empty() &&
        metadata_list->front().rtp_timestamp == encoded_image->Timestamp()) {
      result.emplace(metadata_list->front().encode_start_time_ms);
      encoded_image->capture_time_ms_ =
          metadata_list->front().timestamp_us / 1000;
      encoded_image->ntp_time_ms_ = metadata_list->front().ntp_time_ms;
      encoded_image->rotation_ = metadata_list->front().rotation;
      encoded_image->SetColorSpace(metadata_list->front().color_space);
      encoded_image->SetPacketInfos(metadata_list->front().packet_infos);
      metadata_list->pop_front();
    } else {
      ++reordered_frames_logged_messages_;
      if (reordered_frames_logged_messages_ <= kMessagesThrottlingThreshold ||
          reordered_frames_logged_messages_ % kThrottleRatio == 0) {
        RTC_LOG(LS_WARNING) << "Frame with no encode started time recordings. "
                               "Encoder may be reordering frames "
                               "or not preserving RTP timestamps.";
        if (reordered_frames_logged_messages_ == kMessagesThrottlingThreshold) {
          RTC_LOG(LS_WARNING) << "Too many log messages. Further frames "
                                 "reordering warnings will be throttled.";
        }
      }
    }
  }
  return result;
}

size_t FrameEncodeMetadataWriter::NumSpatialLayers() const {
  size_t num_spatial_layers = codec_settings_.numberOfSimulcastStreams;
  if (codec_settings_.codecType == kVideoCodecVP9) {
    num_spatial_layers = std::max(
        num_spatial_layers,
        static_cast<size_t>(codec_settings_.VP9().numberOfSpatialLayers));
  }
  return std::max(num_spatial_layers, size_t{1});
}

}  // namespace webrtc
<commit_msg>Correctly process disabled streams in FrameEncodeMetadataWriter<commit_after>/*
 *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "video/frame_encode_metadata_writer.h"

#include <algorithm>
#include <memory>
#include <utility>

#include "common_video/h264/sps_vui_rewriter.h"
#include "modules/include/module_common_types_public.h"
#include "modules/video_coding/include/video_coding_defines.h"
#include "rtc_base/logging.h"
#include "rtc_base/ref_counted_object.h"
#include "rtc_base/time_utils.h"

namespace webrtc {
namespace {
const int kMessagesThrottlingThreshold = 2;
const int kThrottleRatio = 100000;

class EncodedImageBufferWrapper : public EncodedImageBufferInterface {
 public:
  explicit EncodedImageBufferWrapper(rtc::Buffer&& buffer)
      : buffer_(std::move(buffer)) {}

  const uint8_t* data() const override { return buffer_.data(); }
  uint8_t* data() override { return buffer_.data(); }
  size_t size() const override { return buffer_.size(); }

 private:
  rtc::Buffer buffer_;
};

}  // namespace

FrameEncodeMetadataWriter::TimingFramesLayerInfo::TimingFramesLayerInfo() =
    default;
FrameEncodeMetadataWriter::TimingFramesLayerInfo::~TimingFramesLayerInfo() =
    default;

FrameEncodeMetadataWriter::FrameEncodeMetadataWriter(
    EncodedImageCallback* frame_drop_callback)
    : frame_drop_callback_(frame_drop_callback),
      internal_source_(false),
      framerate_fps_(0),
      last_timing_frame_time_ms_(-1),
      reordered_frames_logged_messages_(0),
      stalled_encoder_logged_messages_(0) {
  codec_settings_.timing_frame_thresholds = {-1, 0};
}
FrameEncodeMetadataWriter::~FrameEncodeMetadataWriter() {}

void FrameEncodeMetadataWriter::OnEncoderInit(const VideoCodec& codec,
                                              bool internal_source) {
  rtc::CritScope cs(&lock_);
  codec_settings_ = codec;
  internal_source_ = internal_source;
}

void FrameEncodeMetadataWriter::OnSetRates(
    const VideoBitrateAllocation& bitrate_allocation,
    uint32_t framerate_fps) {
  rtc::CritScope cs(&lock_);
  framerate_fps_ = framerate_fps;
  const size_t num_spatial_layers = NumSpatialLayers();
  if (timing_frames_info_.size() < num_spatial_layers) {
    timing_frames_info_.resize(num_spatial_layers);
  }
  for (size_t i = 0; i < num_spatial_layers; ++i) {
    timing_frames_info_[i].target_bitrate_bytes_per_sec =
        bitrate_allocation.GetSpatialLayerSum(i) / 8;
  }
}

void FrameEncodeMetadataWriter::OnEncodeStarted(const VideoFrame& frame) {
  rtc::CritScope cs(&lock_);
  if (internal_source_) {
    return;
  }

  const size_t num_spatial_layers = NumSpatialLayers();
  timing_frames_info_.resize(num_spatial_layers);
  FrameMetadata metadata;
  metadata.rtp_timestamp = frame.timestamp();
  metadata.encode_start_time_ms = rtc::TimeMillis();
  metadata.ntp_time_ms = frame.ntp_time_ms();
  metadata.timestamp_us = frame.timestamp_us();
  metadata.rotation = frame.rotation();
  metadata.color_space = frame.color_space();
  metadata.packet_infos = frame.packet_infos();
  for (size_t si = 0; si < num_spatial_layers; ++si) {
    RTC_DCHECK(timing_frames_info_[si].frames.empty() ||
               rtc::TimeDiff(
                   frame.render_time_ms(),
                   timing_frames_info_[si].frames.back().timestamp_us / 1000) >=
                   0);
    // If stream is disabled due to low bandwidth OnEncodeStarted still will be
    // called and have to be ignored.
    if (timing_frames_info_[si].target_bitrate_bytes_per_sec == 0)
      continue;
    if (timing_frames_info_[si].frames.size() == kMaxEncodeStartTimeListSize) {
      ++stalled_encoder_logged_messages_;
      if (stalled_encoder_logged_messages_ <= kMessagesThrottlingThreshold ||
          stalled_encoder_logged_messages_ % kThrottleRatio == 0) {
        RTC_LOG(LS_WARNING) << "Too many frames in the encode_start_list."
                               " Did encoder stall?";
        if (stalled_encoder_logged_messages_ == kMessagesThrottlingThreshold) {
          RTC_LOG(LS_WARNING)
              << "Too many log messages. Further stalled encoder"
                 "warnings will be throttled.";
        }
      }
      frame_drop_callback_->OnDroppedFrame(
          EncodedImageCallback::DropReason::kDroppedByEncoder);
      timing_frames_info_[si].frames.pop_front();
    }
    timing_frames_info_[si].frames.emplace_back(metadata);
  }
}

void FrameEncodeMetadataWriter::FillTimingInfo(size_t simulcast_svc_idx,
                                               EncodedImage* encoded_image) {
  rtc::CritScope cs(&lock_);
  absl::optional<size_t> outlier_frame_size;
  absl::optional<int64_t> encode_start_ms;
  uint8_t timing_flags = VideoSendTiming::kNotTriggered;

  int64_t encode_done_ms = rtc::TimeMillis();

  // Encoders with internal sources do not call OnEncodeStarted
  // |timing_frames_info_| may be not filled here.
  if (!internal_source_) {
    encode_start_ms =
        ExtractEncodeStartTimeAndFillMetadata(simulcast_svc_idx, encoded_image);
  }

  if (timing_frames_info_.size() > simulcast_svc_idx) {
    size_t target_bitrate =
        timing_frames_info_[simulcast_svc_idx].target_bitrate_bytes_per_sec;
    if (framerate_fps_ > 0 && target_bitrate > 0) {
      // framerate and target bitrate were reported by encoder.
      size_t average_frame_size = target_bitrate / framerate_fps_;
      outlier_frame_size.emplace(
          average_frame_size *
          codec_settings_.timing_frame_thresholds.outlier_ratio_percent / 100);
    }
  }

  // Outliers trigger timing frames, but do not affect scheduled timing
  // frames.
  if (outlier_frame_size && encoded_image->size() >= *outlier_frame_size) {
    timing_flags |= VideoSendTiming::kTriggeredBySize;
  }

  // Check if it's time to send a timing frame.
  int64_t timing_frame_delay_ms =
      encoded_image->capture_time_ms_ - last_timing_frame_time_ms_;
  // Trigger threshold if it's a first frame, too long passed since the last
  // timing frame, or we already sent timing frame on a different simulcast
  // stream with the same capture time.
  if (last_timing_frame_time_ms_ == -1 ||
      timing_frame_delay_ms >=
          codec_settings_.timing_frame_thresholds.delay_ms ||
      timing_frame_delay_ms == 0) {
    timing_flags |= VideoSendTiming::kTriggeredByTimer;
    last_timing_frame_time_ms_ = encoded_image->capture_time_ms_;
  }

  // Workaround for chromoting encoder: it passes encode start and finished
  // timestamps in |timing_| field, but they (together with capture timestamp)
  // are not in the WebRTC clock.
  if (internal_source_ && encoded_image->timing_.encode_finish_ms > 0 &&
      encoded_image->timing_.encode_start_ms > 0) {
    int64_t clock_offset_ms =
        encode_done_ms - encoded_image->timing_.encode_finish_ms;
    // Translate capture timestamp to local WebRTC clock.
    encoded_image->capture_time_ms_ += clock_offset_ms;
    encoded_image->SetTimestamp(
        static_cast<uint32_t>(encoded_image->capture_time_ms_ * 90));
    encode_start_ms.emplace(encoded_image->timing_.encode_start_ms +
                            clock_offset_ms);
  }

  // If encode start is not available that means that encoder uses internal
  // source. In that case capture timestamp may be from a different clock with a
  // drift relative to rtc::TimeMillis(). We can't use it for Timing frames,
  // because to being sent in the network capture time required to be less than
  // all the other timestamps.
  if (encode_start_ms) {
    encoded_image->SetEncodeTime(*encode_start_ms, encode_done_ms);
    encoded_image->timing_.flags = timing_flags;
  } else {
    encoded_image->timing_.flags = VideoSendTiming::kInvalid;
  }
}

std::unique_ptr<RTPFragmentationHeader>
FrameEncodeMetadataWriter::UpdateBitstream(
    const CodecSpecificInfo* codec_specific_info,
    const RTPFragmentationHeader* fragmentation,
    EncodedImage* encoded_image) {
  if (!codec_specific_info ||
      codec_specific_info->codecType != kVideoCodecH264 || !fragmentation ||
      encoded_image->_frameType != VideoFrameType::kVideoFrameKey) {
    return nullptr;
  }

  rtc::Buffer modified_buffer;
  std::unique_ptr<RTPFragmentationHeader> modified_fragmentation =
      std::make_unique<RTPFragmentationHeader>();
  modified_fragmentation->CopyFrom(*fragmentation);

  // Make sure that the data is not copied if owned by EncodedImage.
  const EncodedImage& buffer = *encoded_image;
  SpsVuiRewriter::ParseOutgoingBitstreamAndRewriteSps(
      buffer, fragmentation->fragmentationVectorSize,
      fragmentation->fragmentationOffset, fragmentation->fragmentationLength,
      encoded_image->ColorSpace(), &modified_buffer,
      modified_fragmentation->fragmentationOffset,
      modified_fragmentation->fragmentationLength);

  encoded_image->SetEncodedData(
      new rtc::RefCountedObject<EncodedImageBufferWrapper>(
          std::move(modified_buffer)));

  return modified_fragmentation;
}

void FrameEncodeMetadataWriter::Reset() {
  rtc::CritScope cs(&lock_);
  for (auto& info : timing_frames_info_) {
    info.frames.clear();
  }
  last_timing_frame_time_ms_ = -1;
  reordered_frames_logged_messages_ = 0;
  stalled_encoder_logged_messages_ = 0;
}

absl::optional<int64_t>
FrameEncodeMetadataWriter::ExtractEncodeStartTimeAndFillMetadata(
    size_t simulcast_svc_idx,
    EncodedImage* encoded_image) {
  absl::optional<int64_t> result;
  size_t num_simulcast_svc_streams = timing_frames_info_.size();
  if (simulcast_svc_idx < num_simulcast_svc_streams) {
    auto metadata_list = &timing_frames_info_[simulcast_svc_idx].frames;
    // Skip frames for which there was OnEncodeStarted but no OnEncodedImage
    // call. These are dropped by encoder internally.
    // Because some hardware encoders don't preserve capture timestamp we
    // use RTP timestamps here.
    while (!metadata_list->empty() &&
           IsNewerTimestamp(encoded_image->Timestamp(),
                            metadata_list->front().rtp_timestamp)) {
      frame_drop_callback_->OnDroppedFrame(
          EncodedImageCallback::DropReason::kDroppedByEncoder);
      metadata_list->pop_front();
    }

    encoded_image->content_type_ =
        (codec_settings_.mode == VideoCodecMode::kScreensharing)
            ? VideoContentType::SCREENSHARE
            : VideoContentType::UNSPECIFIED;

    if (!metadata_list->empty() &&
        metadata_list->front().rtp_timestamp == encoded_image->Timestamp()) {
      result.emplace(metadata_list->front().encode_start_time_ms);
      encoded_image->capture_time_ms_ =
          metadata_list->front().timestamp_us / 1000;
      encoded_image->ntp_time_ms_ = metadata_list->front().ntp_time_ms;
      encoded_image->rotation_ = metadata_list->front().rotation;
      encoded_image->SetColorSpace(metadata_list->front().color_space);
      encoded_image->SetPacketInfos(metadata_list->front().packet_infos);
      metadata_list->pop_front();
    } else {
      ++reordered_frames_logged_messages_;
      if (reordered_frames_logged_messages_ <= kMessagesThrottlingThreshold ||
          reordered_frames_logged_messages_ % kThrottleRatio == 0) {
        RTC_LOG(LS_WARNING) << "Frame with no encode started time recordings. "
                               "Encoder may be reordering frames "
                               "or not preserving RTP timestamps.";
        if (reordered_frames_logged_messages_ == kMessagesThrottlingThreshold) {
          RTC_LOG(LS_WARNING) << "Too many log messages. Further frames "
                                 "reordering warnings will be throttled.";
        }
      }
    }
  }
  return result;
}

size_t FrameEncodeMetadataWriter::NumSpatialLayers() const {
  size_t num_spatial_layers = codec_settings_.numberOfSimulcastStreams;
  if (codec_settings_.codecType == kVideoCodecVP9) {
    num_spatial_layers = std::max(
        num_spatial_layers,
        static_cast<size_t>(codec_settings_.VP9().numberOfSpatialLayers));
  }
  return std::max(num_spatial_layers, size_t{1});
}

}  // namespace webrtc
<|endoftext|>