<commit_before>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "base/audio/audio_output_win.h"

#include "base/logging.h"
#include "base/audio/win/audio_util_win.h"
#include "base/audio/win/scoped_mmcss_registration.h"
#include "base/threading/simple_thread.h"
#include "base/win/scoped_com_initializer.h"

namespace base {

namespace {

const char* sessionStateToString(AudioSessionState state)
{
    switch (state)
    {
        case AudioSessionStateActive:
            return "Active";
        case AudioSessionStateInactive:
            return "Inactive";
        case AudioSessionStateExpired:
            return "Expired";
        default:
            return "Invalid";
    }
}

} // namespace

AudioOutputWin::AudioOutputWin(const NeedMoreDataCB& need_more_data_cb)
    : AudioOutput(need_more_data_cb)
{
    // Create the event which the audio engine will signal each time a buffer becomes ready to be
    // processed by the client.
    audio_samples_event_.reset(CreateEventW(nullptr, false, false, nullptr));
    DCHECK(audio_samples_event_.isValid());

    // Event to be set in Stop() when rendering/capturing shall stop.
    stop_event_.reset(CreateEventW(nullptr, false, false, nullptr));
    DCHECK(stop_event_.isValid());

    // Event to be set when it has been detected that an active device has been invalidated or the
    // stream format has changed.
    restart_event_.reset(CreateEventW(nullptr, false, false, nullptr));
    DCHECK(restart_event_.isValid());

    is_initialized_ = init();
}

AudioOutputWin::~AudioOutputWin()
{
    stop();
}

bool AudioOutputWin::start()
{
    if (!is_initialized_)
        return false;

    if (is_restarting_)
    {
        DCHECK(audio_thread_);
    }

    if (!fillRenderEndpointBufferWithSilence(audio_client_.Get(), audio_render_client_.Get()))
    {
        LOG(LS_WARNING) << "Failed to prepare output endpoint with silence";
    }

    num_frames_written_ = endpoint_buffer_size_frames_;

    if (!audio_thread_)
    {
        audio_thread_ = std::make_unique<SimpleThread>();
        audio_thread_->start(std::bind(&AudioOutputWin::threadRun, this));

        if (!audio_thread_->isRunning())
        {
            stopThread();
            LOG(LS_ERROR) << "Failed to start audio thread";
            return false;
        }
    }

    HRESULT hr = audio_client_->Start();
    if (FAILED(hr))
    {
        stopThread();
        LOG(LS_ERROR) << "IAudioClient::Start failed: " << SystemError(hr).toString();
        return false;
    }

    is_active_ = true;
    return true;
}

bool AudioOutputWin::stop()
{
    if (!is_initialized_)
        return true;

    if (!is_active_)
    {
        DLOG(LS_WARNING) << "No output stream is active";
        releaseCOMObjects();
        is_initialized_ = false;
        return true;
    }

    // Stop audio streaming.
    HRESULT hr = audio_client_->Stop();
    if (FAILED(hr))
    {
        LOG(LS_ERROR) << "IAudioClient::Stop failed: " << SystemError(hr).toString();
    }

    // Stop and destroy the audio thread but only when a restart attempt is not ongoing.
    if (!is_restarting_)
        stopThread();

    hr = audio_client_->Reset();
    if (FAILED(hr))
    {
        LOG(LS_ERROR) << "IAudioClient::Reset failed: " << SystemError(hr).toString();
    }

    // Extra safety check to ensure that the buffers are cleared. If the buffers are not cleared
    // correctly, the next call to start() would fail with AUDCLNT_E_BUFFER_ERROR at
    // IAudioRenderClient::GetBuffer().
    UINT32 num_queued_frames = 0;
    audio_client_->GetCurrentPadding(&num_queued_frames);
    DCHECK_EQ(0u, num_queued_frames);

    // Release all allocated COM interfaces to allow for a restart without intermediate destruction.
    releaseCOMObjects();
    return true;
}

void AudioOutputWin::threadRun()
{
    if (!isMMCSSSupported())
    {
        LOG(LS_ERROR) << "MMCSS is not supported";
        return;
    }

    ScopedMMCSSRegistration mmcss_registration(L"Pro Audio");
    win::ScopedCOMInitializer com_initializer(win::ScopedCOMInitializer::kMTA);

    DCHECK(mmcss_registration.isSucceeded());
    DCHECK(com_initializer.isSucceeded());
    DCHECK(stop_event_.isValid());
    DCHECK(audio_samples_event_.isValid());

    bool streaming = true;
    bool error = false;
    HANDLE wait_array[] = { stop_event_.get(), restart_event_.get(), audio_samples_event_.get() };

    // Keep streaming audio until the stop event or the stream-switch event
    // is signaled. An error event can also break the main thread loop.
    while (streaming && !error)
    {
        // Wait for a close-down event, stream-switch event or a new render event.
        DWORD wait_result = WaitForMultipleObjects(
            std::size(wait_array), wait_array, false, INFINITE);
        switch (wait_result)
        {
            case WAIT_OBJECT_0 + 0:
                // |stop_event_| has been set.
                streaming = false;
                break;
            case WAIT_OBJECT_0 + 1:
                // |restart_event_| has been set.
                error = !handleRestartEvent();
                break;
            case WAIT_OBJECT_0 + 2:
                // |audio_samples_event_| has been set.
                error = !handleDataRequest();
                break;
            default:
                error = true;
                break;
        }
    }

    if (streaming && error)
    {
        LOG(LS_ERROR) << "WASAPI streaming failed";
        // Stop audio streaming since something has gone wrong in our main thread loop. Note that,
        // we are still in a "started" state, hence a stop() call is required to join the thread
        // properly.
        HRESULT hr = audio_client_->Stop();
        if (FAILED(hr))
        {
            LOG(LS_ERROR) << "IAudioClient::Stop failed: " << SystemError(hr).toString();
        }
    }
}

bool AudioOutputWin::init()
{
    Microsoft::WRL::ComPtr<IMMDevice> device(createDevice());
    if (!device.Get())
        return false;

    Microsoft::WRL::ComPtr<IAudioClient> audio_client = createClient(device.Get());
    if (!audio_client.Get())
        return false;

    // Define the output WAVEFORMATEXTENSIBLE format in |format_|.
    WAVEFORMATEXTENSIBLE format_extensible;
    memset(&format_extensible, 0, sizeof(format_extensible));

    WAVEFORMATEX& format = format_extensible.Format;
    format.wFormatTag      = WAVE_FORMAT_EXTENSIBLE;
    format.nChannels       = kChannels;
    format.nSamplesPerSec  = kSampleRate;
    format.wBitsPerSample  = kBitsPerSample;
    format.nBlockAlign     = (format.wBitsPerSample / 8) * format.nChannels;
    format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
    format.cbSize          = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);

    // Add the parts which are unique for the WAVE_FORMAT_EXTENSIBLE structure.
    format_extensible.Samples.wValidBitsPerSample = kBitsPerSample;
    format_extensible.dwChannelMask               = KSAUDIO_SPEAKER_STEREO;
    format_extensible.SubFormat                   = KSDATAFORMAT_SUBTYPE_PCM;

    if (!isFormatSupported(audio_client.Get(), AUDCLNT_SHAREMODE_SHARED, &format_extensible))
        return false;

    // Initialize the audio stream between the client and the device in shared mode using
    // event-driven buffer handling. Also, using 0 as requested buffer size results in a default
    // (minimum) endpoint buffer size.
    const REFERENCE_TIME requested_buffer_size = 0;
    if (!sharedModeInitialize(audio_client.Get(), &format_extensible, audio_samples_event_,
                              requested_buffer_size, true, &endpoint_buffer_size_frames_))
    {
        return false;
    }

    // Create an IAudioRenderClient for an initialized IAudioClient. The IAudioRenderClient
    // interface enables us to write output data to a rendering endpoint buffer.
    Microsoft::WRL::ComPtr<IAudioRenderClient> audio_render_client =
        createRenderClient(audio_client.Get());
    if (!audio_render_client.Get())
        return false;

    // Create an AudioSessionControl interface given the initialized client. The IAudioControl
    // interface enables a client to configure the control parameters for an audio session and to
    // monitor events in the session.
    Microsoft::WRL::ComPtr<IAudioSessionControl> audio_session_control =
        createAudioSessionControl(audio_client.Get());
    if (!audio_session_control.Get())
        return false;

    // The Sndvol program displays volume and mute controls for sessions that are in the active and
    // inactive states.
    AudioSessionState state;
    if (FAILED(audio_session_control->GetState(&state)))
        return false;

    LOG(LS_INFO) << "Audio session state: " << sessionStateToString(state);

    // Register the client to receive notifications of session events, including changes in the
    // stream state.
    if (FAILED(audio_session_control->RegisterAudioSessionNotification(this)))
    {
        LOG(LS_ERROR) << "IAudioSessionControl::RegisterAudioSessionNotification failed";
        return false;
    }

    // Store valid COM interfaces.
    audio_client_ = audio_client;
    audio_render_client_ = audio_render_client;
    audio_session_control_ = audio_session_control;
    return true;
}

bool AudioOutputWin::handleDataRequest()
{
    // Get the padding value which indicates the amount of valid unread data that the endpoint
    // buffer currently contains.
    UINT32 num_unread_frames = 0;
    HRESULT hr = audio_client_->GetCurrentPadding(&num_unread_frames);
    if (hr == AUDCLNT_E_DEVICE_INVALIDATED)
    {
        // Avoid breaking the thread loop implicitly by returning false and return true instead for
        // AUDCLNT_E_DEVICE_INVALIDATED even it is a valid error message. We will use notifications
        // about device changes instead to stop data callbacks and attempt to restart streaming.
        DLOG(LS_ERROR) << "AUDCLNT_E_DEVICE_INVALIDATED";
        return true;
    }

    if (FAILED(hr))
    {
        LOG(LS_ERROR) << "IAudioClient::GetCurrentPadding failed: " << SystemError(hr).toString();
        return false;
    }

    // Contains how much new data we can write to the buffer without the risk of overwriting
    // previously written data that the audio engine has not yet read from the buffer. I.e., it is
    // the maximum buffer size we can request when calling IAudioRenderClient::GetBuffer().
    UINT32 num_requested_frames = endpoint_buffer_size_frames_ - num_unread_frames;
    if (num_requested_frames == 0)
    {
        DLOG(LS_WARNING) << "Audio thread is signaled but no new audio samples are needed";
        return true;
    }

    // Request all available space in the rendering endpoint buffer into which the client can later
    // write an audio packet.
    uint8_t* audio_data;
    hr = audio_render_client_->GetBuffer(num_requested_frames, &audio_data);
    if (FAILED(hr))
    {
        LOG(LS_ERROR) << "IAudioRenderClient::GetBuffer failed: " << SystemError(hr).toString();
        return false;
    }

    // Get audio data and write it to the allocated buffer in |audio_data|. The playout latency is
    // not updated for each callback.
    onDataRequest(reinterpret_cast<int16_t*>(audio_data), num_requested_frames * kChannels);

    // Release the buffer space acquired in IAudioRenderClient::GetBuffer.
    hr = audio_render_client_->ReleaseBuffer(num_requested_frames, 0);
    if (FAILED(hr))
    {
        LOG(LS_ERROR) << "IAudioRenderClient::ReleaseBuffer failed: "
                      << SystemError(hr).toString();
        return false;
    }

    num_frames_written_ += num_requested_frames;
    return true;
}

bool AudioOutputWin::handleRestartEvent()
{
    DCHECK(audio_thread_);
    DCHECK(is_restarting_);

    if (!is_initialized_ || !is_active_)
        return true;

    if (!stop())
        return false;

    if (!init())
        return false;

    if (!start())
        return false;

    return true;
}

void AudioOutputWin::stopThread()
{
    DCHECK(!is_restarting_);

    if (audio_thread_)
    {
        if (audio_thread_->isRunning())
        {
            SetEvent(stop_event_);
            audio_thread_->stop();
        }

        audio_thread_.reset();

        // Ensure that we don't quit the main thread loop immediately next time start() is called.
        ResetEvent(stop_event_);
        ResetEvent(restart_event_);
    }
}

void AudioOutputWin::releaseCOMObjects()
{
    if (audio_client_)
        audio_client_.Reset();

    if (audio_session_control_.Get())
        audio_session_control_.Reset();

    if (audio_render_client_.Get())
        audio_render_client_.Reset();
}

ULONG AudioOutputWin::AddRef()
{
    ULONG new_ref = InterlockedIncrement(&ref_count_);
    return new_ref;
}

ULONG AudioOutputWin::Release()
{
    ULONG new_ref = InterlockedDecrement(&ref_count_);
    return new_ref;
}

HRESULT AudioOutputWin::QueryInterface(REFIID iid, void** object)
{
    if (object == nullptr)
        return E_POINTER;

    if (iid == IID_IUnknown || iid == __uuidof(IAudioSessionEvents))
    {
        *object = static_cast<IAudioSessionEvents*>(this);
        return S_OK;
    };

    *object = nullptr;
    return E_NOINTERFACE;
}

HRESULT AudioOutputWin::OnStateChanged(AudioSessionState new_state)
{
    return S_OK;
}

HRESULT AudioOutputWin::OnSessionDisconnected(AudioSessionDisconnectReason disconnect_reason)
{
    if (is_restarting_)
    {
        DLOG(LS_WARNING) << "Ignoring since restart is already active";
        return S_OK;
    }

    // Internal test method which can be used in tests to emulate a restart signal. It simply sets
    // the same event which is normally triggered by session and device notifications. Hence, the
    // emulated restart sequence covers most parts of a real sequence expect the actual device
    // switch.
    if (disconnect_reason == DisconnectReasonDeviceRemoval ||
        disconnect_reason == DisconnectReasonFormatChanged)
    {
        is_restarting_ = true;
        SetEvent(restart_event_);
    }
    return S_OK;
}

HRESULT AudioOutputWin::OnDisplayNameChanged(LPCWSTR new_display_name, LPCGUID event_context)
{
    return S_OK;
}

HRESULT AudioOutputWin::OnIconPathChanged(LPCWSTR new_icon_path, LPCGUID event_context)
{
    return S_OK;
}

HRESULT AudioOutputWin::OnSimpleVolumeChanged(
    float new_simple_volume, BOOL new_mute, LPCGUID event_context)
{
    return S_OK;
}

HRESULT AudioOutputWin::OnChannelVolumeChanged(
    DWORD channel_count, float new_channel_volumes[], DWORD changed_channel, LPCGUID event_context)
{
    return S_OK;
}

HRESULT AudioOutputWin::OnGroupingParamChanged(LPCGUID new_grouping_param, LPCGUID event_context)
{
    return S_OK;
}

} // namespace base
<commit_msg>Set priority for audio thread.<commit_after>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "base/audio/audio_output_win.h"

#include "base/logging.h"
#include "base/audio/win/audio_util_win.h"
#include "base/audio/win/scoped_mmcss_registration.h"
#include "base/threading/simple_thread.h"
#include "base/win/scoped_com_initializer.h"

namespace base {

namespace {

const char* sessionStateToString(AudioSessionState state)
{
    switch (state)
    {
        case AudioSessionStateActive:
            return "Active";
        case AudioSessionStateInactive:
            return "Inactive";
        case AudioSessionStateExpired:
            return "Expired";
        default:
            return "Invalid";
    }
}

} // namespace

AudioOutputWin::AudioOutputWin(const NeedMoreDataCB& need_more_data_cb)
    : AudioOutput(need_more_data_cb)
{
    // Create the event which the audio engine will signal each time a buffer becomes ready to be
    // processed by the client.
    audio_samples_event_.reset(CreateEventW(nullptr, false, false, nullptr));
    DCHECK(audio_samples_event_.isValid());

    // Event to be set in Stop() when rendering/capturing shall stop.
    stop_event_.reset(CreateEventW(nullptr, false, false, nullptr));
    DCHECK(stop_event_.isValid());

    // Event to be set when it has been detected that an active device has been invalidated or the
    // stream format has changed.
    restart_event_.reset(CreateEventW(nullptr, false, false, nullptr));
    DCHECK(restart_event_.isValid());

    is_initialized_ = init();
}

AudioOutputWin::~AudioOutputWin()
{
    stop();
}

bool AudioOutputWin::start()
{
    if (!is_initialized_)
        return false;

    if (is_restarting_)
    {
        DCHECK(audio_thread_);
    }

    if (!fillRenderEndpointBufferWithSilence(audio_client_.Get(), audio_render_client_.Get()))
    {
        LOG(LS_WARNING) << "Failed to prepare output endpoint with silence";
    }

    num_frames_written_ = endpoint_buffer_size_frames_;

    if (!audio_thread_)
    {
        audio_thread_ = std::make_unique<SimpleThread>();
        audio_thread_->start(std::bind(&AudioOutputWin::threadRun, this));

        if (!audio_thread_->isRunning())
        {
            stopThread();
            LOG(LS_ERROR) << "Failed to start audio thread";
            return false;
        }
    }

    HRESULT hr = audio_client_->Start();
    if (FAILED(hr))
    {
        stopThread();
        LOG(LS_ERROR) << "IAudioClient::Start failed: " << SystemError(hr).toString();
        return false;
    }

    is_active_ = true;
    return true;
}

bool AudioOutputWin::stop()
{
    if (!is_initialized_)
        return true;

    if (!is_active_)
    {
        DLOG(LS_WARNING) << "No output stream is active";
        releaseCOMObjects();
        is_initialized_ = false;
        return true;
    }

    // Stop audio streaming.
    HRESULT hr = audio_client_->Stop();
    if (FAILED(hr))
    {
        LOG(LS_ERROR) << "IAudioClient::Stop failed: " << SystemError(hr).toString();
    }

    // Stop and destroy the audio thread but only when a restart attempt is not ongoing.
    if (!is_restarting_)
        stopThread();

    hr = audio_client_->Reset();
    if (FAILED(hr))
    {
        LOG(LS_ERROR) << "IAudioClient::Reset failed: " << SystemError(hr).toString();
    }

    // Extra safety check to ensure that the buffers are cleared. If the buffers are not cleared
    // correctly, the next call to start() would fail with AUDCLNT_E_BUFFER_ERROR at
    // IAudioRenderClient::GetBuffer().
    UINT32 num_queued_frames = 0;
    audio_client_->GetCurrentPadding(&num_queued_frames);
    DCHECK_EQ(0u, num_queued_frames);

    // Release all allocated COM interfaces to allow for a restart without intermediate destruction.
    releaseCOMObjects();
    return true;
}

void AudioOutputWin::threadRun()
{
    if (!isMMCSSSupported())
    {
        LOG(LS_ERROR) << "MMCSS is not supported";
        return;
    }

    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);

    ScopedMMCSSRegistration mmcss_registration(L"Pro Audio");
    win::ScopedCOMInitializer com_initializer(win::ScopedCOMInitializer::kMTA);

    DCHECK(mmcss_registration.isSucceeded());
    DCHECK(com_initializer.isSucceeded());
    DCHECK(stop_event_.isValid());
    DCHECK(audio_samples_event_.isValid());

    bool streaming = true;
    bool error = false;
    HANDLE wait_array[] = { stop_event_.get(), restart_event_.get(), audio_samples_event_.get() };

    // Keep streaming audio until the stop event or the stream-switch event
    // is signaled. An error event can also break the main thread loop.
    while (streaming && !error)
    {
        // Wait for a close-down event, stream-switch event or a new render event.
        DWORD wait_result = WaitForMultipleObjects(
            std::size(wait_array), wait_array, false, INFINITE);
        switch (wait_result)
        {
            case WAIT_OBJECT_0 + 0:
                // |stop_event_| has been set.
                streaming = false;
                break;
            case WAIT_OBJECT_0 + 1:
                // |restart_event_| has been set.
                error = !handleRestartEvent();
                break;
            case WAIT_OBJECT_0 + 2:
                // |audio_samples_event_| has been set.
                error = !handleDataRequest();
                break;
            default:
                error = true;
                break;
        }
    }

    if (streaming && error)
    {
        LOG(LS_ERROR) << "WASAPI streaming failed";
        // Stop audio streaming since something has gone wrong in our main thread loop. Note that,
        // we are still in a "started" state, hence a stop() call is required to join the thread
        // properly.
        HRESULT hr = audio_client_->Stop();
        if (FAILED(hr))
        {
            LOG(LS_ERROR) << "IAudioClient::Stop failed: " << SystemError(hr).toString();
        }
    }
}

bool AudioOutputWin::init()
{
    Microsoft::WRL::ComPtr<IMMDevice> device(createDevice());
    if (!device.Get())
        return false;

    Microsoft::WRL::ComPtr<IAudioClient> audio_client = createClient(device.Get());
    if (!audio_client.Get())
        return false;

    // Define the output WAVEFORMATEXTENSIBLE format in |format_|.
    WAVEFORMATEXTENSIBLE format_extensible;
    memset(&format_extensible, 0, sizeof(format_extensible));

    WAVEFORMATEX& format = format_extensible.Format;
    format.wFormatTag      = WAVE_FORMAT_EXTENSIBLE;
    format.nChannels       = kChannels;
    format.nSamplesPerSec  = kSampleRate;
    format.wBitsPerSample  = kBitsPerSample;
    format.nBlockAlign     = (format.wBitsPerSample / 8) * format.nChannels;
    format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
    format.cbSize          = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);

    // Add the parts which are unique for the WAVE_FORMAT_EXTENSIBLE structure.
    format_extensible.Samples.wValidBitsPerSample = kBitsPerSample;
    format_extensible.dwChannelMask               = KSAUDIO_SPEAKER_STEREO;
    format_extensible.SubFormat                   = KSDATAFORMAT_SUBTYPE_PCM;

    if (!isFormatSupported(audio_client.Get(), AUDCLNT_SHAREMODE_SHARED, &format_extensible))
        return false;

    // Initialize the audio stream between the client and the device in shared mode using
    // event-driven buffer handling. Also, using 0 as requested buffer size results in a default
    // (minimum) endpoint buffer size.
    const REFERENCE_TIME requested_buffer_size = 0;
    if (!sharedModeInitialize(audio_client.Get(), &format_extensible, audio_samples_event_,
                              requested_buffer_size, true, &endpoint_buffer_size_frames_))
    {
        return false;
    }

    // Create an IAudioRenderClient for an initialized IAudioClient. The IAudioRenderClient
    // interface enables us to write output data to a rendering endpoint buffer.
    Microsoft::WRL::ComPtr<IAudioRenderClient> audio_render_client =
        createRenderClient(audio_client.Get());
    if (!audio_render_client.Get())
        return false;

    // Create an AudioSessionControl interface given the initialized client. The IAudioControl
    // interface enables a client to configure the control parameters for an audio session and to
    // monitor events in the session.
    Microsoft::WRL::ComPtr<IAudioSessionControl> audio_session_control =
        createAudioSessionControl(audio_client.Get());
    if (!audio_session_control.Get())
        return false;

    // The Sndvol program displays volume and mute controls for sessions that are in the active and
    // inactive states.
    AudioSessionState state;
    if (FAILED(audio_session_control->GetState(&state)))
        return false;

    LOG(LS_INFO) << "Audio session state: " << sessionStateToString(state);

    // Register the client to receive notifications of session events, including changes in the
    // stream state.
    if (FAILED(audio_session_control->RegisterAudioSessionNotification(this)))
    {
        LOG(LS_ERROR) << "IAudioSessionControl::RegisterAudioSessionNotification failed";
        return false;
    }

    // Store valid COM interfaces.
    audio_client_ = audio_client;
    audio_render_client_ = audio_render_client;
    audio_session_control_ = audio_session_control;
    return true;
}

bool AudioOutputWin::handleDataRequest()
{
    // Get the padding value which indicates the amount of valid unread data that the endpoint
    // buffer currently contains.
    UINT32 num_unread_frames = 0;
    HRESULT hr = audio_client_->GetCurrentPadding(&num_unread_frames);
    if (hr == AUDCLNT_E_DEVICE_INVALIDATED)
    {
        // Avoid breaking the thread loop implicitly by returning false and return true instead for
        // AUDCLNT_E_DEVICE_INVALIDATED even it is a valid error message. We will use notifications
        // about device changes instead to stop data callbacks and attempt to restart streaming.
        DLOG(LS_ERROR) << "AUDCLNT_E_DEVICE_INVALIDATED";
        return true;
    }

    if (FAILED(hr))
    {
        LOG(LS_ERROR) << "IAudioClient::GetCurrentPadding failed: " << SystemError(hr).toString();
        return false;
    }

    // Contains how much new data we can write to the buffer without the risk of overwriting
    // previously written data that the audio engine has not yet read from the buffer. I.e., it is
    // the maximum buffer size we can request when calling IAudioRenderClient::GetBuffer().
    UINT32 num_requested_frames = endpoint_buffer_size_frames_ - num_unread_frames;
    if (num_requested_frames == 0)
    {
        DLOG(LS_WARNING) << "Audio thread is signaled but no new audio samples are needed";
        return true;
    }

    // Request all available space in the rendering endpoint buffer into which the client can later
    // write an audio packet.
    uint8_t* audio_data;
    hr = audio_render_client_->GetBuffer(num_requested_frames, &audio_data);
    if (FAILED(hr))
    {
        LOG(LS_ERROR) << "IAudioRenderClient::GetBuffer failed: " << SystemError(hr).toString();
        return false;
    }

    // Get audio data and write it to the allocated buffer in |audio_data|. The playout latency is
    // not updated for each callback.
    onDataRequest(reinterpret_cast<int16_t*>(audio_data), num_requested_frames * kChannels);

    // Release the buffer space acquired in IAudioRenderClient::GetBuffer.
    hr = audio_render_client_->ReleaseBuffer(num_requested_frames, 0);
    if (FAILED(hr))
    {
        LOG(LS_ERROR) << "IAudioRenderClient::ReleaseBuffer failed: "
                      << SystemError(hr).toString();
        return false;
    }

    num_frames_written_ += num_requested_frames;
    return true;
}

bool AudioOutputWin::handleRestartEvent()
{
    DCHECK(audio_thread_);
    DCHECK(is_restarting_);

    if (!is_initialized_ || !is_active_)
        return true;

    if (!stop())
        return false;

    if (!init())
        return false;

    if (!start())
        return false;

    return true;
}

void AudioOutputWin::stopThread()
{
    DCHECK(!is_restarting_);

    if (audio_thread_)
    {
        if (audio_thread_->isRunning())
        {
            SetEvent(stop_event_);
            audio_thread_->stop();
        }

        audio_thread_.reset();

        // Ensure that we don't quit the main thread loop immediately next time start() is called.
        ResetEvent(stop_event_);
        ResetEvent(restart_event_);
    }
}

void AudioOutputWin::releaseCOMObjects()
{
    if (audio_client_)
        audio_client_.Reset();

    if (audio_session_control_.Get())
        audio_session_control_.Reset();

    if (audio_render_client_.Get())
        audio_render_client_.Reset();
}

ULONG AudioOutputWin::AddRef()
{
    ULONG new_ref = InterlockedIncrement(&ref_count_);
    return new_ref;
}

ULONG AudioOutputWin::Release()
{
    ULONG new_ref = InterlockedDecrement(&ref_count_);
    return new_ref;
}

HRESULT AudioOutputWin::QueryInterface(REFIID iid, void** object)
{
    if (object == nullptr)
        return E_POINTER;

    if (iid == IID_IUnknown || iid == __uuidof(IAudioSessionEvents))
    {
        *object = static_cast<IAudioSessionEvents*>(this);
        return S_OK;
    };

    *object = nullptr;
    return E_NOINTERFACE;
}

HRESULT AudioOutputWin::OnStateChanged(AudioSessionState new_state)
{
    return S_OK;
}

HRESULT AudioOutputWin::OnSessionDisconnected(AudioSessionDisconnectReason disconnect_reason)
{
    if (is_restarting_)
    {
        DLOG(LS_WARNING) << "Ignoring since restart is already active";
        return S_OK;
    }

    // Internal test method which can be used in tests to emulate a restart signal. It simply sets
    // the same event which is normally triggered by session and device notifications. Hence, the
    // emulated restart sequence covers most parts of a real sequence expect the actual device
    // switch.
    if (disconnect_reason == DisconnectReasonDeviceRemoval ||
        disconnect_reason == DisconnectReasonFormatChanged)
    {
        is_restarting_ = true;
        SetEvent(restart_event_);
    }
    return S_OK;
}

HRESULT AudioOutputWin::OnDisplayNameChanged(LPCWSTR new_display_name, LPCGUID event_context)
{
    return S_OK;
}

HRESULT AudioOutputWin::OnIconPathChanged(LPCWSTR new_icon_path, LPCGUID event_context)
{
    return S_OK;
}

HRESULT AudioOutputWin::OnSimpleVolumeChanged(
    float new_simple_volume, BOOL new_mute, LPCGUID event_context)
{
    return S_OK;
}

HRESULT AudioOutputWin::OnChannelVolumeChanged(
    DWORD channel_count, float new_channel_volumes[], DWORD changed_channel, LPCGUID event_context)
{
    return S_OK;
}

HRESULT AudioOutputWin::OnGroupingParamChanged(LPCGUID new_grouping_param, LPCGUID event_context)
{
    return S_OK;
}

} // namespace base
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: property.cxx,v $
 *
 *  $Revision: 1.17 $
 *
 *  last change: $Author: kz $ $Date: 2007-05-10 09:59:17 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_forms.hxx"

#ifndef FRM_STRINGS_HXX
#include "frm_strings.hxx"
#endif

#ifndef _FRM_PROPERTY_HXX_
#include "property.hxx"
#endif

#ifndef _FRM_PROPERTY_HRC_
#include "property.hrc"
#endif

#ifndef _CPPUHELPER_QUERYINTERFACE_HXX_
#include <cppuhelper/queryinterface.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif

#include <algorithm>

//... namespace frm .......................................................
namespace frm
{
//.........................................................................

//==================================================================
//= PropertyInfoService
//==================================================================
PropertyInfoService::PropertyMap PropertyInfoService::s_AllKnownProperties;
//------------------------------------------------------------------
sal_Int32 PropertyInfoService::getPropertyId(const ::rtl::OUString& _rName)
{
    initialize();

    PropertyAssignment aCompareName(_rName, -1);

    ::std::pair<PropertyMapIterator,PropertyMapIterator> aPair = equal_range(
        s_AllKnownProperties.begin(),
        s_AllKnownProperties.end(),
        aCompareName,
        PropertyAssignmentNameCompareLess());

    sal_Int32 nHandle = -1;
    if (aPair.first != aPair.second)
    {   // we found something _and_ we have an identity
        nHandle = aPair.first->nHandle;
    }

    return nHandle;
}

//------------------------------------------------------------------
sal_Int32 ConcreteInfoService::getPreferedPropertyId(const ::rtl::OUString& _rName)
{
    return PropertyInfoService::getPropertyId(_rName);
}

//------------------------------------------------------------------
#define ADD_PROP_ASSIGNMENT(varname) \
    s_AllKnownProperties.push_back(PropertyAssignment(PROPERTY_##varname, PROPERTY_ID_##varname))
//..................................................................
void PropertyInfoService::initialize()
{
    if (!s_AllKnownProperties.empty())
        return;

    s_AllKnownProperties.reserve(220);

    ADD_PROP_ASSIGNMENT(NAME);
    ADD_PROP_ASSIGNMENT(TAG);
    ADD_PROP_ASSIGNMENT(TABINDEX);
    ADD_PROP_ASSIGNMENT(CLASSID);
    ADD_PROP_ASSIGNMENT(ALIGN);
    ADD_PROP_ASSIGNMENT(FETCHSIZE);
    ADD_PROP_ASSIGNMENT(VALUE);
    ADD_PROP_ASSIGNMENT(VALUEMIN);
    ADD_PROP_ASSIGNMENT(VALUEMAX);
    ADD_PROP_ASSIGNMENT(VALUESTEP);
    ADD_PROP_ASSIGNMENT(TEXT);
    ADD_PROP_ASSIGNMENT(LABEL);
    ADD_PROP_ASSIGNMENT(NAVIGATION);
    ADD_PROP_ASSIGNMENT(CYCLE);
    ADD_PROP_ASSIGNMENT(CONTROLSOURCE);
    ADD_PROP_ASSIGNMENT(ENABLED);
    ADD_PROP_ASSIGNMENT(SPIN);
    ADD_PROP_ASSIGNMENT(READONLY);
    ADD_PROP_ASSIGNMENT(FILTER);
    ADD_PROP_ASSIGNMENT(WIDTH);
    ADD_PROP_ASSIGNMENT(SEARCHABLE);
    ADD_PROP_ASSIGNMENT(MULTILINE);
    ADD_PROP_ASSIGNMENT(TARGET_URL);
    ADD_PROP_ASSIGNMENT(DEFAULTCONTROL);
    ADD_PROP_ASSIGNMENT(MAXTEXTLEN);
    ADD_PROP_ASSIGNMENT(SIZE);
    ADD_PROP_ASSIGNMENT(DATE);
    ADD_PROP_ASSIGNMENT(TIME);
    ADD_PROP_ASSIGNMENT(STATE);
    ADD_PROP_ASSIGNMENT(TRISTATE);
    ADD_PROP_ASSIGNMENT(HIDDEN_VALUE);
    ADD_PROP_ASSIGNMENT(TARGET_FRAME);
    ADD_PROP_ASSIGNMENT(BUTTONTYPE);
    ADD_PROP_ASSIGNMENT(STRINGITEMLIST);
    ADD_PROP_ASSIGNMENT(DEFAULT_TEXT);
    ADD_PROP_ASSIGNMENT(DEFAULTCHECKED);
    ADD_PROP_ASSIGNMENT(DEFAULT_DATE);
    ADD_PROP_ASSIGNMENT(DEFAULT_TIME);
    ADD_PROP_ASSIGNMENT(DEFAULT_VALUE);
    ADD_PROP_ASSIGNMENT(FORMATKEY);
    ADD_PROP_ASSIGNMENT(FORMATSSUPPLIER);
    ADD_PROP_ASSIGNMENT(SUBMIT_ACTION);
    ADD_PROP_ASSIGNMENT(SUBMIT_TARGET);
    ADD_PROP_ASSIGNMENT(SUBMIT_METHOD);
    ADD_PROP_ASSIGNMENT(SUBMIT_ENCODING);
    ADD_PROP_ASSIGNMENT(IMAGE_URL);
    ADD_PROP_ASSIGNMENT(EMPTY_IS_NULL);
    ADD_PROP_ASSIGNMENT(LISTSOURCETYPE);
    ADD_PROP_ASSIGNMENT(LISTSOURCE);
    ADD_PROP_ASSIGNMENT(SELECT_SEQ);
    ADD_PROP_ASSIGNMENT(VALUE_SEQ);
    ADD_PROP_ASSIGNMENT(DEFAULT_SELECT_SEQ);
    ADD_PROP_ASSIGNMENT(MULTISELECTION);
    ADD_PROP_ASSIGNMENT(DECIMAL_ACCURACY);
    ADD_PROP_ASSIGNMENT(EDITMASK);
    ADD_PROP_ASSIGNMENT(ISREADONLY);
    ADD_PROP_ASSIGNMENT(FIELDTYPE);
    ADD_PROP_ASSIGNMENT(DECIMALS);
    ADD_PROP_ASSIGNMENT(REFVALUE);
    ADD_PROP_ASSIGNMENT(STRICTFORMAT);
    ADD_PROP_ASSIGNMENT(DATASOURCE);
    ADD_PROP_ASSIGNMENT(ALLOWADDITIONS);
    ADD_PROP_ASSIGNMENT(ALLOWEDITS);
    ADD_PROP_ASSIGNMENT(ALLOWDELETIONS);
    ADD_PROP_ASSIGNMENT(MASTERFIELDS);
    ADD_PROP_ASSIGNMENT(ISPASSTHROUGH);
    ADD_PROP_ASSIGNMENT(QUERY);
    ADD_PROP_ASSIGNMENT(LITERALMASK);
    ADD_PROP_ASSIGNMENT(SHOWTHOUSANDSEP);
    ADD_PROP_ASSIGNMENT(CURRENCYSYMBOL);
    ADD_PROP_ASSIGNMENT(DATEFORMAT);
    ADD_PROP_ASSIGNMENT(DATEMIN);
    ADD_PROP_ASSIGNMENT(DATEMAX);
    ADD_PROP_ASSIGNMENT(DATE_SHOW_CENTURY);
    ADD_PROP_ASSIGNMENT(TIMEFORMAT);
    ADD_PROP_ASSIGNMENT(TIMEMIN);
    ADD_PROP_ASSIGNMENT(TIMEMAX);
    ADD_PROP_ASSIGNMENT(LINECOUNT);
    ADD_PROP_ASSIGNMENT(BOUNDCOLUMN);
    ADD_PROP_ASSIGNMENT(HASNAVIGATION);
    ADD_PROP_ASSIGNMENT(FONT);
    ADD_PROP_ASSIGNMENT(BACKGROUNDCOLOR);
    ADD_PROP_ASSIGNMENT(FILLCOLOR);
    ADD_PROP_ASSIGNMENT(TEXTCOLOR);
    ADD_PROP_ASSIGNMENT(LINECOLOR);
    ADD_PROP_ASSIGNMENT(BORDER);
    ADD_PROP_ASSIGNMENT(DROPDOWN);
    ADD_PROP_ASSIGNMENT(HSCROLL);
    ADD_PROP_ASSIGNMENT(VSCROLL);
    ADD_PROP_ASSIGNMENT(TABSTOP);
    ADD_PROP_ASSIGNMENT(AUTOCOMPLETE);
    ADD_PROP_ASSIGNMENT(HARDLINEBREAKS);
    ADD_PROP_ASSIGNMENT(PRINTABLE);
    ADD_PROP_ASSIGNMENT(ECHO_CHAR);
    ADD_PROP_ASSIGNMENT(ROWHEIGHT);
    ADD_PROP_ASSIGNMENT(HELPTEXT);
    ADD_PROP_ASSIGNMENT(FONT_NAME);
    ADD_PROP_ASSIGNMENT(FONT_STYLENAME);
    ADD_PROP_ASSIGNMENT(FONT_FAMILY);
    ADD_PROP_ASSIGNMENT(FONT_CHARSET);
    ADD_PROP_ASSIGNMENT(FONT_HEIGHT);
    ADD_PROP_ASSIGNMENT(FONT_WEIGHT);
    ADD_PROP_ASSIGNMENT(FONT_SLANT);
    ADD_PROP_ASSIGNMENT(FONT_UNDERLINE);
    ADD_PROP_ASSIGNMENT(FONT_WORDLINEMODE);
    ADD_PROP_ASSIGNMENT(FONT_STRIKEOUT);
    ADD_PROP_ASSIGNMENT(TEXTLINECOLOR);
    ADD_PROP_ASSIGNMENT(FONTEMPHASISMARK);
    ADD_PROP_ASSIGNMENT(FONTRELIEF);
    ADD_PROP_ASSIGNMENT(HELPURL);
    ADD_PROP_ASSIGNMENT(RECORDMARKER);
    ADD_PROP_ASSIGNMENT(BOUNDFIELD);
    ADD_PROP_ASSIGNMENT(TREATASNUMERIC);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_VALUE);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_DEFAULT);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_MIN);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_MAX);
    ADD_PROP_ASSIGNMENT(HIDDEN);
    ADD_PROP_ASSIGNMENT(FILTERPROPOSAL);
    ADD_PROP_ASSIGNMENT(FIELDSOURCE);
    ADD_PROP_ASSIGNMENT(TABLENAME);
    ADD_PROP_ASSIGNMENT(CONTROLLABEL);
    ADD_PROP_ASSIGNMENT(CURRSYM_POSITION);
    ADD_PROP_ASSIGNMENT(CURSORCOLOR);
    ADD_PROP_ASSIGNMENT(ALWAYSSHOWCURSOR);
    ADD_PROP_ASSIGNMENT(DISPLAYSYNCHRON);
    ADD_PROP_ASSIGNMENT(ISMODIFIED);
    ADD_PROP_ASSIGNMENT(ISNEW);
    ADD_PROP_ASSIGNMENT(PRIVILEGES);
    ADD_PROP_ASSIGNMENT(DETAILFIELDS);
    ADD_PROP_ASSIGNMENT(COMMAND);
    ADD_PROP_ASSIGNMENT(COMMANDTYPE);
    ADD_PROP_ASSIGNMENT(RESULTSET_CONCURRENCY);
    ADD_PROP_ASSIGNMENT(INSERTONLY);
    ADD_PROP_ASSIGNMENT(RESULTSET_TYPE);
    ADD_PROP_ASSIGNMENT(ESCAPE_PROCESSING);
    ADD_PROP_ASSIGNMENT(APPLYFILTER);
    ADD_PROP_ASSIGNMENT(ISNULLABLE);
    ADD_PROP_ASSIGNMENT(ACTIVECOMMAND);
    ADD_PROP_ASSIGNMENT(ISCURRENCY);
    ADD_PROP_ASSIGNMENT(URL);
    ADD_PROP_ASSIGNMENT(TITLE);
    ADD_PROP_ASSIGNMENT(ACTIVE_CONNECTION);
    ADD_PROP_ASSIGNMENT(SCALE);
    ADD_PROP_ASSIGNMENT(SORT);
    ADD_PROP_ASSIGNMENT(PERSISTENCE_MAXTEXTLENGTH);
    ADD_PROP_ASSIGNMENT(SCROLL_VALUE);
    ADD_PROP_ASSIGNMENT(SPIN_VALUE);
    ADD_PROP_ASSIGNMENT(DEFAULT_SCROLL_VALUE);
    ADD_PROP_ASSIGNMENT(DEFAULT_SPIN_VALUE);

    // now sort the array by name

    std::sort(
        s_AllKnownProperties.begin(),
        s_AllKnownProperties.end(),
        PropertyAssignmentNameCompareLess()
    );
}

//.........................................................................
}
//... namespace frm .......................................................

<commit_msg>INTEGRATION: CWS changefileheader (1.17.78); FILE MERGED 2008/04/01 15:16:37 thb 1.17.78.3: #i85898# Stripping all external header guards 2008/04/01 12:30:29 thb 1.17.78.2: #i85898# Stripping all external header guards 2008/03/31 13:11:40 rt 1.17.78.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: property.cxx,v $
 * $Revision: 1.18 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_forms.hxx"
#include "frm_strings.hxx"
#include "property.hxx"

#ifndef _FRM_PROPERTY_HRC_
#include "property.hrc"
#endif
#include <cppuhelper/queryinterface.hxx>
#include <tools/debug.hxx>
#include <com/sun/star/beans/PropertyAttribute.hpp>

#include <algorithm>

//... namespace frm .......................................................
namespace frm
{
//.........................................................................

//==================================================================
//= PropertyInfoService
//==================================================================
PropertyInfoService::PropertyMap PropertyInfoService::s_AllKnownProperties;
//------------------------------------------------------------------
sal_Int32 PropertyInfoService::getPropertyId(const ::rtl::OUString& _rName)
{
    initialize();

    PropertyAssignment aCompareName(_rName, -1);

    ::std::pair<PropertyMapIterator,PropertyMapIterator> aPair = equal_range(
        s_AllKnownProperties.begin(),
        s_AllKnownProperties.end(),
        aCompareName,
        PropertyAssignmentNameCompareLess());

    sal_Int32 nHandle = -1;
    if (aPair.first != aPair.second)
    {   // we found something _and_ we have an identity
        nHandle = aPair.first->nHandle;
    }

    return nHandle;
}

//------------------------------------------------------------------
sal_Int32 ConcreteInfoService::getPreferedPropertyId(const ::rtl::OUString& _rName)
{
    return PropertyInfoService::getPropertyId(_rName);
}

//------------------------------------------------------------------
#define ADD_PROP_ASSIGNMENT(varname) \
    s_AllKnownProperties.push_back(PropertyAssignment(PROPERTY_##varname, PROPERTY_ID_##varname))
//..................................................................
void PropertyInfoService::initialize()
{
    if (!s_AllKnownProperties.empty())
        return;

    s_AllKnownProperties.reserve(220);

    ADD_PROP_ASSIGNMENT(NAME);
    ADD_PROP_ASSIGNMENT(TAG);
    ADD_PROP_ASSIGNMENT(TABINDEX);
    ADD_PROP_ASSIGNMENT(CLASSID);
    ADD_PROP_ASSIGNMENT(ALIGN);
    ADD_PROP_ASSIGNMENT(FETCHSIZE);
    ADD_PROP_ASSIGNMENT(VALUE);
    ADD_PROP_ASSIGNMENT(VALUEMIN);
    ADD_PROP_ASSIGNMENT(VALUEMAX);
    ADD_PROP_ASSIGNMENT(VALUESTEP);
    ADD_PROP_ASSIGNMENT(TEXT);
    ADD_PROP_ASSIGNMENT(LABEL);
    ADD_PROP_ASSIGNMENT(NAVIGATION);
    ADD_PROP_ASSIGNMENT(CYCLE);
    ADD_PROP_ASSIGNMENT(CONTROLSOURCE);
    ADD_PROP_ASSIGNMENT(ENABLED);
    ADD_PROP_ASSIGNMENT(SPIN);
    ADD_PROP_ASSIGNMENT(READONLY);
    ADD_PROP_ASSIGNMENT(FILTER);
    ADD_PROP_ASSIGNMENT(WIDTH);
    ADD_PROP_ASSIGNMENT(SEARCHABLE);
    ADD_PROP_ASSIGNMENT(MULTILINE);
    ADD_PROP_ASSIGNMENT(TARGET_URL);
    ADD_PROP_ASSIGNMENT(DEFAULTCONTROL);
    ADD_PROP_ASSIGNMENT(MAXTEXTLEN);
    ADD_PROP_ASSIGNMENT(SIZE);
    ADD_PROP_ASSIGNMENT(DATE);
    ADD_PROP_ASSIGNMENT(TIME);
    ADD_PROP_ASSIGNMENT(STATE);
    ADD_PROP_ASSIGNMENT(TRISTATE);
    ADD_PROP_ASSIGNMENT(HIDDEN_VALUE);
    ADD_PROP_ASSIGNMENT(TARGET_FRAME);
    ADD_PROP_ASSIGNMENT(BUTTONTYPE);
    ADD_PROP_ASSIGNMENT(STRINGITEMLIST);
    ADD_PROP_ASSIGNMENT(DEFAULT_TEXT);
    ADD_PROP_ASSIGNMENT(DEFAULTCHECKED);
    ADD_PROP_ASSIGNMENT(DEFAULT_DATE);
    ADD_PROP_ASSIGNMENT(DEFAULT_TIME);
    ADD_PROP_ASSIGNMENT(DEFAULT_VALUE);
    ADD_PROP_ASSIGNMENT(FORMATKEY);
    ADD_PROP_ASSIGNMENT(FORMATSSUPPLIER);
    ADD_PROP_ASSIGNMENT(SUBMIT_ACTION);
    ADD_PROP_ASSIGNMENT(SUBMIT_TARGET);
    ADD_PROP_ASSIGNMENT(SUBMIT_METHOD);
    ADD_PROP_ASSIGNMENT(SUBMIT_ENCODING);
    ADD_PROP_ASSIGNMENT(IMAGE_URL);
    ADD_PROP_ASSIGNMENT(EMPTY_IS_NULL);
    ADD_PROP_ASSIGNMENT(LISTSOURCETYPE);
    ADD_PROP_ASSIGNMENT(LISTSOURCE);
    ADD_PROP_ASSIGNMENT(SELECT_SEQ);
    ADD_PROP_ASSIGNMENT(VALUE_SEQ);
    ADD_PROP_ASSIGNMENT(DEFAULT_SELECT_SEQ);
    ADD_PROP_ASSIGNMENT(MULTISELECTION);
    ADD_PROP_ASSIGNMENT(DECIMAL_ACCURACY);
    ADD_PROP_ASSIGNMENT(EDITMASK);
    ADD_PROP_ASSIGNMENT(ISREADONLY);
    ADD_PROP_ASSIGNMENT(FIELDTYPE);
    ADD_PROP_ASSIGNMENT(DECIMALS);
    ADD_PROP_ASSIGNMENT(REFVALUE);
    ADD_PROP_ASSIGNMENT(STRICTFORMAT);
    ADD_PROP_ASSIGNMENT(DATASOURCE);
    ADD_PROP_ASSIGNMENT(ALLOWADDITIONS);
    ADD_PROP_ASSIGNMENT(ALLOWEDITS);
    ADD_PROP_ASSIGNMENT(ALLOWDELETIONS);
    ADD_PROP_ASSIGNMENT(MASTERFIELDS);
    ADD_PROP_ASSIGNMENT(ISPASSTHROUGH);
    ADD_PROP_ASSIGNMENT(QUERY);
    ADD_PROP_ASSIGNMENT(LITERALMASK);
    ADD_PROP_ASSIGNMENT(SHOWTHOUSANDSEP);
    ADD_PROP_ASSIGNMENT(CURRENCYSYMBOL);
    ADD_PROP_ASSIGNMENT(DATEFORMAT);
    ADD_PROP_ASSIGNMENT(DATEMIN);
    ADD_PROP_ASSIGNMENT(DATEMAX);
    ADD_PROP_ASSIGNMENT(DATE_SHOW_CENTURY);
    ADD_PROP_ASSIGNMENT(TIMEFORMAT);
    ADD_PROP_ASSIGNMENT(TIMEMIN);
    ADD_PROP_ASSIGNMENT(TIMEMAX);
    ADD_PROP_ASSIGNMENT(LINECOUNT);
    ADD_PROP_ASSIGNMENT(BOUNDCOLUMN);
    ADD_PROP_ASSIGNMENT(HASNAVIGATION);
    ADD_PROP_ASSIGNMENT(FONT);
    ADD_PROP_ASSIGNMENT(BACKGROUNDCOLOR);
    ADD_PROP_ASSIGNMENT(FILLCOLOR);
    ADD_PROP_ASSIGNMENT(TEXTCOLOR);
    ADD_PROP_ASSIGNMENT(LINECOLOR);
    ADD_PROP_ASSIGNMENT(BORDER);
    ADD_PROP_ASSIGNMENT(DROPDOWN);
    ADD_PROP_ASSIGNMENT(HSCROLL);
    ADD_PROP_ASSIGNMENT(VSCROLL);
    ADD_PROP_ASSIGNMENT(TABSTOP);
    ADD_PROP_ASSIGNMENT(AUTOCOMPLETE);
    ADD_PROP_ASSIGNMENT(HARDLINEBREAKS);
    ADD_PROP_ASSIGNMENT(PRINTABLE);
    ADD_PROP_ASSIGNMENT(ECHO_CHAR);
    ADD_PROP_ASSIGNMENT(ROWHEIGHT);
    ADD_PROP_ASSIGNMENT(HELPTEXT);
    ADD_PROP_ASSIGNMENT(FONT_NAME);
    ADD_PROP_ASSIGNMENT(FONT_STYLENAME);
    ADD_PROP_ASSIGNMENT(FONT_FAMILY);
    ADD_PROP_ASSIGNMENT(FONT_CHARSET);
    ADD_PROP_ASSIGNMENT(FONT_HEIGHT);
    ADD_PROP_ASSIGNMENT(FONT_WEIGHT);
    ADD_PROP_ASSIGNMENT(FONT_SLANT);
    ADD_PROP_ASSIGNMENT(FONT_UNDERLINE);
    ADD_PROP_ASSIGNMENT(FONT_WORDLINEMODE);
    ADD_PROP_ASSIGNMENT(FONT_STRIKEOUT);
    ADD_PROP_ASSIGNMENT(TEXTLINECOLOR);
    ADD_PROP_ASSIGNMENT(FONTEMPHASISMARK);
    ADD_PROP_ASSIGNMENT(FONTRELIEF);
    ADD_PROP_ASSIGNMENT(HELPURL);
    ADD_PROP_ASSIGNMENT(RECORDMARKER);
    ADD_PROP_ASSIGNMENT(BOUNDFIELD);
    ADD_PROP_ASSIGNMENT(TREATASNUMERIC);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_VALUE);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_DEFAULT);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_MIN);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_MAX);
    ADD_PROP_ASSIGNMENT(HIDDEN);
    ADD_PROP_ASSIGNMENT(FILTERPROPOSAL);
    ADD_PROP_ASSIGNMENT(FIELDSOURCE);
    ADD_PROP_ASSIGNMENT(TABLENAME);
    ADD_PROP_ASSIGNMENT(CONTROLLABEL);
    ADD_PROP_ASSIGNMENT(CURRSYM_POSITION);
    ADD_PROP_ASSIGNMENT(CURSORCOLOR);
    ADD_PROP_ASSIGNMENT(ALWAYSSHOWCURSOR);
    ADD_PROP_ASSIGNMENT(DISPLAYSYNCHRON);
    ADD_PROP_ASSIGNMENT(ISMODIFIED);
    ADD_PROP_ASSIGNMENT(ISNEW);
    ADD_PROP_ASSIGNMENT(PRIVILEGES);
    ADD_PROP_ASSIGNMENT(DETAILFIELDS);
    ADD_PROP_ASSIGNMENT(COMMAND);
    ADD_PROP_ASSIGNMENT(COMMANDTYPE);
    ADD_PROP_ASSIGNMENT(RESULTSET_CONCURRENCY);
    ADD_PROP_ASSIGNMENT(INSERTONLY);
    ADD_PROP_ASSIGNMENT(RESULTSET_TYPE);
    ADD_PROP_ASSIGNMENT(ESCAPE_PROCESSING);
    ADD_PROP_ASSIGNMENT(APPLYFILTER);
    ADD_PROP_ASSIGNMENT(ISNULLABLE);
    ADD_PROP_ASSIGNMENT(ACTIVECOMMAND);
    ADD_PROP_ASSIGNMENT(ISCURRENCY);
    ADD_PROP_ASSIGNMENT(URL);
    ADD_PROP_ASSIGNMENT(TITLE);
    ADD_PROP_ASSIGNMENT(ACTIVE_CONNECTION);
    ADD_PROP_ASSIGNMENT(SCALE);
    ADD_PROP_ASSIGNMENT(SORT);
    ADD_PROP_ASSIGNMENT(PERSISTENCE_MAXTEXTLENGTH);
    ADD_PROP_ASSIGNMENT(SCROLL_VALUE);
    ADD_PROP_ASSIGNMENT(SPIN_VALUE);
    ADD_PROP_ASSIGNMENT(DEFAULT_SCROLL_VALUE);
    ADD_PROP_ASSIGNMENT(DEFAULT_SPIN_VALUE);

    // now sort the array by name

    std::sort(
        s_AllKnownProperties.begin(),
        s_AllKnownProperties.end(),
        PropertyAssignmentNameCompareLess()
    );
}

//.........................................................................
}
//... namespace frm .......................................................

<|endoftext|>


<commit_before>/*
 * Modularity.cpp
 *
 *  Created on: 10.12.2012
 *      Author: cls
 */

#include "Modularity.h"

namespace EnsembleClustering {

Modularity::Modularity() : QualityMeasure() {
}

Modularity::~Modularity() {
	// TODO Auto-generated destructor stub
}

double Modularity::getQuality(const Clustering& zeta, Graph& G) {
	assert (G.numberOfNodes() <= zeta.numberOfNodes());

	DEBUG("m = " << G.numberOfEdges());
	DEBUG("l = " << G.numberOfSelfLoops());

	Coverage coverage;
	double cov = coverage.getQuality(zeta, G); // deprecated: intraEdgeWeightSum / totalEdgeWeight;
	DEBUG("coverage = " << cov);
	double expCov; // term $\frac{ \sum_{C \in \zeta}( \sum_{v \in C} \omega(v) )^2 }{4( \sum_{e \in E} \omega(e) )^2 }$
	double modularity; 	// mod = coverage - expected coverage
	double totalEdgeWeight = G.totalEdgeWeight(); // add edge weight
	DEBUG("total edge weight: " << totalEdgeWeight)

	if (totalEdgeWeight == 0.0) {
		ERROR("G: m=" << G.numberOfEdges() << "n=" << G.numberOfNodes());
		throw std::invalid_argument("Modularity is undefined for graphs without edges (including self-loops).");
	}

	IndexMap<cluster, double> incidentWeightSum(zeta.upperBound(), 0.0);	//!< cluster -> sum of the weights of incident edges for all nodes

	// compute volume of each cluster
	G.forNodes([&](node v){
		// add to cluster weight
		cluster c = zeta[v];
		assert (zeta.lowerBound() <= c);
		assert (c < zeta.upperBound());
		incidentWeightSum[c] += G.weightedDegree(v) + G.weight(v,v); // account for self-loops a second time
	});

	// compute sum of squared cluster volumes and divide by squared graph volume
	// double totalIncidentWeight = 0.0; 	//!< term $\sum_{C \in \zeta}( \sum_{v \in C} \omega(v) )^2 $
	expCov = 0.0;
//	double divisor = 4 * totalEdgeWeight * totalEdgeWeight;
//	assert (divisor != 0);	// do not divide by 0

	#pragma omp parallel for reduction(+:expCov)
	for (cluster c = zeta.lowerBound(); c < zeta.upperBound(); ++c) {
		expCov += ((incidentWeightSum[c] / totalEdgeWeight) * (incidentWeightSum[c] / totalEdgeWeight )) / 4;	// squared
	}

	DEBUG("expected coverage: " << expCov);

	DEBUG("expected coverage: " << expCov);

	// assert ranges of coverage
	assert(cov <= 1.0);
	assert(cov >= 0.0);
	assert(expCov <= 1.0);
	assert(expCov >= 0.0);

	modularity = cov - expCov;

	assert(! std::isnan(modularity));	// do not return NaN
	// do not return anything not in the range of modularity values
	assert(modularity >= -0.5);
	assert(modularity <= 1);
	return modularity;
}

} /* namespace EnsembleClustering */
<commit_msg>debug statements in modularity<commit_after>/*
 * Modularity.cpp
 *
 *  Created on: 10.12.2012
 *      Author: cls
 */

#include "Modularity.h"

namespace EnsembleClustering {

Modularity::Modularity() : QualityMeasure() {
}

Modularity::~Modularity() {
	// TODO Auto-generated destructor stub
}

double Modularity::getQuality(const Clustering& zeta, Graph& G) {
	assert (G.numberOfNodes() <= zeta.numberOfNodes());

	DEBUG("m = " << G.numberOfEdges());
	DEBUG("l = " << G.numberOfSelfLoops());

	Coverage coverage;
	double cov = coverage.getQuality(zeta, G); // deprecated: intraEdgeWeightSum / totalEdgeWeight;
	DEBUG("coverage = " << cov);
	double expCov; // term $\frac{ \sum_{C \in \zeta}( \sum_{v \in C} \omega(v) )^2 }{4( \sum_{e \in E} \omega(e) )^2 }$
	double modularity; 	// mod = coverage - expected coverage
	double totalEdgeWeight = G.totalEdgeWeight(); // add edge weight
	DEBUG("total edge weight: " << totalEdgeWeight)

	if (totalEdgeWeight == 0.0) {
		ERROR("G: m=" << G.numberOfEdges() << "n=" << G.numberOfNodes());
		throw std::invalid_argument("Modularity is undefined for graphs without edges (including self-loops).");
	}

	IndexMap<cluster, double> incidentWeightSum(zeta.upperBound(), 0.0);	//!< cluster -> sum of the weights of incident edges for all nodes

	// compute volume of each cluster
	G.forNodes([&](node v){
		// add to cluster weight
		cluster c = zeta[v];
		assert (zeta.lowerBound() <= c);
		assert (c < zeta.upperBound());
		incidentWeightSum[c] += G.weightedDegree(v) + G.weight(v,v); // account for self-loops a second time
	});

	// compute sum of squared cluster volumes and divide by squared graph volume
	// double totalIncidentWeight = 0.0; 	//!< term $\sum_{C \in \zeta}( \sum_{v \in C} \omega(v) )^2 $
	expCov = 0.0;
//	double divisor = 4 * totalEdgeWeight * totalEdgeWeight;
//	assert (divisor != 0);	// do not divide by 0

	#pragma omp parallel for reduction(+:expCov)
	for (cluster c = zeta.lowerBound(); c < zeta.upperBound(); ++c) {
		expCov += ((incidentWeightSum[c] / totalEdgeWeight) * (incidentWeightSum[c] / totalEdgeWeight )) / 4;	// squared
	}

	DEBUG("expected coverage: " << expCov);

	// assert ranges of coverage
	assert(cov <= 1.0);
	assert(cov >= 0.0);
	assert(expCov <= 1.0);
	assert(expCov >= 0.0);

	modularity = cov - expCov;
	DEBUG("modularity = " << modularity)

	assert(! std::isnan(modularity));	// do not return NaN
	// do not return anything not in the range of modularity values
	assert(modularity >= -0.5);
	assert(modularity <= 1);
	return modularity;
}

} /* namespace EnsembleClustering */
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// abstract_backend.h
//
// Identification: src/backend/storage/backend_file.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "backend/storage/backend_file.h"
#include "backend/logging/log_manager.h"
#include <fcntl.h>
#include <sys/mman.h>
#include <fstream>
#include <unistd.h>

namespace peloton {
namespace storage {

BackendFile::BackendFile() {
  if (EnableBackFileType()) {
    // create a big file
    std::ofstream backend_file(file_name, std::ios::binary | std::ios::out);
    backend_file.seekp(file_size - 1);
    backend_file.write("", 1);

    // do mmap
    fd = open(file_name.c_str(), O_RDWR, 0);
    backend_space = (char *) mmap(nullptr, file_size, PROT_READ | PROT_WRITE,
                                  MAP_FILE | MAP_SHARED, fd, 0);
    close(fd);
    assert(backend_space != nullptr);
    // create vmem pool
    vmp = vmem_create_in_region(backend_space, file_size);
    assert(vmp != nullptr);
  }
}

BackendFile::~BackendFile() {
  if (vmp != nullptr) {
    vmem_delete(vmp);
  }
  if (backend_space != nullptr) {
    munmap(backend_space, file_size);
    //remove(file_name.c_str());
  }
}

void *BackendFile::Allocate(size_t size) {
  if (backend_space != nullptr) {
    return vmem_malloc(vmp, size);;
  } else {
    return ::operator new(size);
  }
}

void BackendFile::Free(void *ptr) {
  if (backend_space != nullptr) {
    vmem_free(vmp, ptr);
  } else {
    ::operator delete(ptr);
  }
}

void BackendFile::Sync(void *ptr) {
  if (backend_space != nullptr) {
    size_t ptr_size = vmem_malloc_usable_size(vmp, ptr);
    if (ptr_size != 0) {
      msync(ptr, ptr_size, MS_SYNC);
    }
  }
}

}  // End storage namespace
}  // End peloton namespace
<commit_msg>Backend file should finish creating file before map it.<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// abstract_backend.h
//
// Identification: src/backend/storage/backend_file.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "backend/storage/backend_file.h"
#include "backend/logging/log_manager.h"
#include <fcntl.h>
#include <sys/mman.h>
#include <fstream>
#include <unistd.h>

namespace peloton {
namespace storage {

BackendFile::BackendFile() {
  if (EnableBackFileType()) {
    // create a big file
    std::ofstream backend_file(file_name, std::ios::binary | std::ios::out);
    backend_file.seekp(file_size - 1);
    backend_file.write("", 1);
    backend_file.close();

    // do mmap
    fd = open(file_name.c_str(), O_RDWR, 0);
    backend_space = (char *) mmap(nullptr, file_size, PROT_READ | PROT_WRITE,
                                  MAP_FILE | MAP_SHARED, fd, 0);
    close(fd);
    assert(backend_space != nullptr);
    // create vmem pool
    vmp = vmem_create_in_region(backend_space, file_size);
    assert(vmp != nullptr);
  }
}

BackendFile::~BackendFile() {
  if (vmp != nullptr) {
    vmem_delete(vmp);
  }
  if (backend_space != nullptr) {
    munmap(backend_space, file_size);
    //remove(file_name.c_str());
  }
}

void *BackendFile::Allocate(size_t size) {
  if (backend_space != nullptr) {
    return vmem_malloc(vmp, size);;
  } else {
    return ::operator new(size);
  }
}

void BackendFile::Free(void *ptr) {
  if (backend_space != nullptr) {
    vmem_free(vmp, ptr);
  } else {
    ::operator delete(ptr);
  }
}

void BackendFile::Sync(void *ptr) {
  if (backend_space != nullptr) {
    size_t ptr_size = vmem_malloc_usable_size(vmp, ptr);
    if (ptr_size != 0) {
      msync(ptr, ptr_size, MS_SYNC);
    }
  }
}

}  // End storage namespace
}  // End peloton namespace
<|endoftext|>


<commit_before>/* This file is part of the Palabos library.
 *
 * Copyright (C) 2011-2015 FlowKit Sarl
 * Route d'Oron 2
 * 1010 Lausanne, Switzerland
 * E-mail contact: contact@flowkit.com
 *
 * The most recent release of Palabos can be downloaded at
 * <http://www.palabos.org/>
 *
 * The library Palabos is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * The 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef TRT_DYNAMICS_HH
#define TRT_DYNAMICS_HH

#include "complexDynamics/trtDynamics.h"
#include "latticeBoltzmann/dynamicsTemplates.h"
#include "latticeBoltzmann/momentTemplates.h"
#include "core/latticeStatistics.h"
#include <algorithm>
#include <limits>

namespace plb {

/* *************** Class TRTdynamics *********************************************** */

template<typename T, template<typename U> class Descriptor>
const T TRTdynamics<T,Descriptor>::sMinus = 1.1;

template<typename T, template<typename U> class Descriptor>
int TRTdynamics<T,Descriptor>::id =
    meta::registerOneParamDynamics<T,Descriptor,TRTdynamics<T,Descriptor> >("TRT");

/** \param omega_ relaxation parameter, related to the dynamic viscosity
 */
template<typename T, template<typename U> class Descriptor>
TRTdynamics<T,Descriptor>::TRTdynamics(T omega_ )
    : IsoThermalBulkDynamics<T,Descriptor>(omega_)
{ }

template<typename T, template<typename U> class Descriptor>
TRTdynamics<T,Descriptor>* TRTdynamics<T,Descriptor>::clone() const {
    return new TRTdynamics<T,Descriptor>(*this);
}

template<typename T, template<typename U> class Descriptor>
int TRTdynamics<T,Descriptor>::getId() const {
    return id;
}

template<typename T, template<typename U> class Descriptor>
void TRTdynamics<T,Descriptor>::collide (
        Cell<T,Descriptor>& cell, BlockStatistics& statistics )
{
    const T sPlus = this->getOmega();

    Array<T,Descriptor<T>::q> eq;
    // In the following, we number the plus/minus variables from 1 to (Q-1)/2.
    // So we allocate the index-zero memory location, and waste some memory
    // for convenience.
    Array<T,Descriptor<T>::q/2+1> eq_plus, eq_minus, f_plus, f_minus;

    Array<T,3> j;
    T rhoBar;
    momentTemplates<T,Descriptor>::get_rhoBar_j(cell, rhoBar, j);
    T jSqr = normSqr(j);
    T invRho = Descriptor<T>::invRho(rhoBar);
    dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibria(rhoBar, invRho, j, jSqr, eq);

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        eq_plus[i]  = 0.5*(eq[i] + eq[i+Descriptor<T>::q/2]);
        eq_minus[i] = 0.5*(eq[i] - eq[i+Descriptor<T>::q/2]);
        f_plus[i]   = 0.5*(cell[i] + cell[i+Descriptor<T>::q/2]);
        f_minus[i]  = 0.5*(cell[i] - cell[i+Descriptor<T>::q/2]);
    }

    cell[0] += -sPlus*cell[0] + sPlus*eq[0];

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        cell[i] += -sPlus*(f_plus[i]-eq_plus[i]) - sMinus*(f_minus[i]-eq_minus[i]);
        cell[i+Descriptor<T>::q/2] += -sPlus*(f_plus[i]-eq_plus[i]) + sMinus*(f_minus[i]-eq_minus[i]);
    }

    if (cell.takesStatistics()) {
        gatherStatistics(statistics, rhoBar, jSqr * invRho * invRho );
    }
}

template<typename T, template<typename U> class Descriptor>
void TRTdynamics<T,Descriptor>::collideExternal (
        Cell<T,Descriptor>& cell, T rhoBar, Array<T,Descriptor<T>::d> const& j,
        T thetaBar, BlockStatistics& statistics )
{
    const T sPlus = this->getOmega();

    Array<T,Descriptor<T>::q> eq;
    // In the following, we number the plus/minus variables from 1 to (Q-1)/2.
    // So we allocate the index-zero memory location, and waste some memory
    // for convenience.
    Array<T,Descriptor<T>::q/2+1> eq_plus, eq_minus, f_plus, f_minus;

    T jSqr = normSqr(j);
    T invRho = Descriptor<T>::invRho(rhoBar);
    dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibria(rhoBar, invRho, j, jSqr, eq);

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        eq_plus[i]  = 0.5*(eq[i] + eq[i+Descriptor<T>::q/2]);
        eq_minus[i] = 0.5*(eq[i] - eq[i+Descriptor<T>::q/2]);
        f_plus[i]   = 0.5*(cell[i] + cell[i+Descriptor<T>::q/2]);
        f_minus[i]  = 0.5*(cell[i] - cell[i+Descriptor<T>::q/2]);
    }

    cell[0] += -sPlus*cell[0] + sPlus*eq[0];

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        cell[i] += -sPlus*(f_plus[i]-eq_plus[i]) - sMinus*(f_minus[i]-eq_minus[i]);
        cell[i+Descriptor<T>::q/2] += -sPlus*(f_plus[i]-eq_plus[i]) + sMinus*(f_minus[i]-eq_minus[i]);
    }

    if (cell.takesStatistics()) {
        gatherStatistics(statistics, rhoBar, jSqr * Descriptor<T>::invRho(rhoBar) * Descriptor<T>::invRho(rhoBar) );
    }
}

template<typename T, template<typename U> class Descriptor>
T TRTdynamics<T,Descriptor>::computeEquilibrium(plint iPop, T rhoBar, Array<T,Descriptor<T>::d> const& j,
                                                T jSqr, T thetaBar) const
{
    T invRho = Descriptor<T>::invRho(rhoBar);
    return dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibrium(iPop, rhoBar, invRho, j, jSqr);
}

/* *************** Class IncTRTdynamics *********************************************** */

template<typename T, template<typename U> class Descriptor>
const T IncTRTdynamics<T,Descriptor>::sMinus = 1.1;

template<typename T, template<typename U> class Descriptor>
int IncTRTdynamics<T,Descriptor>::id =
    meta::registerOneParamDynamics<T,Descriptor,IncTRTdynamics<T,Descriptor> >("IncTRT");

/** \param omega_ relaxation parameter, related to the dynamic viscosity
 */
template<typename T, template<typename U> class Descriptor>
IncTRTdynamics<T,Descriptor>::IncTRTdynamics(T omega_ )
    : IsoThermalBulkDynamics<T,Descriptor>(omega_)
{ }

template<typename T, template<typename U> class Descriptor>
IncTRTdynamics<T,Descriptor>* IncTRTdynamics<T,Descriptor>::clone() const {
    return new IncTRTdynamics<T,Descriptor>(*this);
}

template<typename T, template<typename U> class Descriptor>
int IncTRTdynamics<T,Descriptor>::getId() const {
    return id;
}

template<typename T, template<typename U> class Descriptor>
void IncTRTdynamics<T,Descriptor>::collide (
        Cell<T,Descriptor>& cell, BlockStatistics& statistics )
{
    const T sPlus = this->getOmega();

    Array<T,Descriptor<T>::q> eq;
    // In the following, we number the plus/minus variables from 1 to (Q-1)/2.
    // So we allocate the index-zero memory location, and waste some memory
    // for convenience.
    Array<T,Descriptor<T>::q/2+1> eq_plus, eq_minus, f_plus, f_minus;

    Array<T,3> j;
    T rhoBar;
    momentTemplates<T,Descriptor>::get_rhoBar_j(cell, rhoBar, j);
    T jSqr = normSqr(j);
    T invRho0 = 1.;
    dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibria(rhoBar, invRho0, j, jSqr, eq);

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        eq_plus[i]  = 0.5*(eq[i] + eq[i+Descriptor<T>::q/2]);
        eq_minus[i] = 0.5*(eq[i] - eq[i+Descriptor<T>::q/2]);
        f_plus[i]   = 0.5*(cell[i] + cell[i+Descriptor<T>::q/2]);
        f_minus[i]  = 0.5*(cell[i] - cell[i+Descriptor<T>::q/2]);
    }

    cell[0] += -sPlus*cell[0] + sPlus*eq[0];

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        cell[i] += -sPlus*(f_plus[i]-eq_plus[i]) - sMinus*(f_minus[i]-eq_minus[i]);
        cell[i+Descriptor<T>::q/2] += -sPlus*(f_plus[i]-eq_plus[i]) + sMinus*(f_minus[i]-eq_minus[i]);
    }

    if (cell.takesStatistics()) {
        gatherStatistics(statistics, rhoBar, jSqr);
    }
}

template<typename T, template<typename U> class Descriptor>
void IncTRTdynamics<T,Descriptor>::collideExternal (
        Cell<T,Descriptor>& cell, T rhoBar, Array<T,Descriptor<T>::d> const& j,
        T thetaBar, BlockStatistics& statistics )
{
    const T sPlus = this->getOmega();

    Array<T,Descriptor<T>::q> eq;
    // In the following, we number the plus/minus variables from 1 to (Q-1)/2.
    // So we allocate the index-zero memory location, and waste some memory
    // for convenience.
    Array<T,Descriptor<T>::q/2+1> eq_plus, eq_minus, f_plus, f_minus;

    T jSqr = normSqr(j);
    T invRho0 = 1.;
    dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibria(rhoBar, invRho0, j, jSqr, eq);

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        eq_plus[i]  = 0.5*(eq[i] + eq[i+Descriptor<T>::q/2]);
        eq_minus[i] = 0.5*(eq[i] - eq[i+Descriptor<T>::q/2]);
        f_plus[i]   = 0.5*(cell[i] + cell[i+Descriptor<T>::q/2]);
        f_minus[i]  = 0.5*(cell[i] - cell[i+Descriptor<T>::q/2]);
    }

    cell[0] += -sPlus*cell[0] + sPlus*eq[0];

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        cell[i] += -sPlus*(f_plus[i]-eq_plus[i]) - sMinus*(f_minus[i]-eq_minus[i]);
        cell[i+Descriptor<T>::q/2] += -sPlus*(f_plus[i]-eq_plus[i]) + sMinus*(f_minus[i]-eq_minus[i]);
    }

    if (cell.takesStatistics()) {
        gatherStatistics(statistics, rhoBar, jSqr);
    }
}

template<typename T, template<typename U> class Descriptor>
T IncTRTdynamics<T,Descriptor>::computeEquilibrium(plint iPop, T rhoBar, Array<T,Descriptor<T>::d> const& j,
                                                T jSqr, T thetaBar) const
{
    return dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibrium(iPop, rhoBar, (T)1, j, jSqr);
}

template<typename T, template<typename U> class Descriptor>
bool IncTRTdynamics<T,Descriptor>::velIsJ() const {
    return true;
}

template<typename T, template<typename U> class Descriptor>
void IncTRTdynamics<T,Descriptor>::computeVelocity( Cell<T,Descriptor> const& cell,
                                                                 Array<T,Descriptor<T>::d>& u ) const
{
    T dummyRhoBar;
    this->computeRhoBarJ(cell, dummyRhoBar, u);
}

}

#endif  // TRT_DYNAMICS_HH

<commit_msg>fixing bug in TRTDynamics: code was limited to 3D simulation only<commit_after>/* This file is part of the Palabos library.
 *
 * Copyright (C) 2011-2015 FlowKit Sarl
 * Route d'Oron 2
 * 1010 Lausanne, Switzerland
 * E-mail contact: contact@flowkit.com
 *
 * The most recent release of Palabos can be downloaded at
 * <http://www.palabos.org/>
 *
 * The library Palabos is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * The 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef TRT_DYNAMICS_HH
#define TRT_DYNAMICS_HH

#include "complexDynamics/trtDynamics.h"
#include "latticeBoltzmann/dynamicsTemplates.h"
#include "latticeBoltzmann/momentTemplates.h"
#include "core/latticeStatistics.h"
#include <algorithm>
#include <limits>

namespace plb {

/* *************** Class TRTdynamics *********************************************** */

template<typename T, template<typename U> class Descriptor>
const T TRTdynamics<T,Descriptor>::sMinus = 1.1;

template<typename T, template<typename U> class Descriptor>
int TRTdynamics<T,Descriptor>::id =
    meta::registerOneParamDynamics<T,Descriptor,TRTdynamics<T,Descriptor> >("TRT");

/** \param omega_ relaxation parameter, related to the dynamic viscosity
 */
template<typename T, template<typename U> class Descriptor>
TRTdynamics<T,Descriptor>::TRTdynamics(T omega_ )
    : IsoThermalBulkDynamics<T,Descriptor>(omega_)
{ }

template<typename T, template<typename U> class Descriptor>
TRTdynamics<T,Descriptor>* TRTdynamics<T,Descriptor>::clone() const {
    return new TRTdynamics<T,Descriptor>(*this);
}

template<typename T, template<typename U> class Descriptor>
int TRTdynamics<T,Descriptor>::getId() const {
    return id;
}

template<typename T, template<typename U> class Descriptor>
void TRTdynamics<T,Descriptor>::collide (
        Cell<T,Descriptor>& cell, BlockStatistics& statistics )
{
    const T sPlus = this->getOmega();

    Array<T,Descriptor<T>::q> eq;
    // In the following, we number the plus/minus variables from 1 to (Q-1)/2.
    // So we allocate the index-zero memory location, and waste some memory
    // for convenience.
    Array<T,Descriptor<T>::q/2+1> eq_plus, eq_minus, f_plus, f_minus;

    Array<T,Descriptor<T>::d> j;
    T rhoBar;
    momentTemplates<T,Descriptor>::get_rhoBar_j(cell, rhoBar, j);
    T jSqr = normSqr(j);
    T invRho = Descriptor<T>::invRho(rhoBar);
    dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibria(rhoBar, invRho, j, jSqr, eq);

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        eq_plus[i]  = 0.5*(eq[i] + eq[i+Descriptor<T>::q/2]);
        eq_minus[i] = 0.5*(eq[i] - eq[i+Descriptor<T>::q/2]);
        f_plus[i]   = 0.5*(cell[i] + cell[i+Descriptor<T>::q/2]);
        f_minus[i]  = 0.5*(cell[i] - cell[i+Descriptor<T>::q/2]);
    }

    cell[0] += -sPlus*cell[0] + sPlus*eq[0];

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        cell[i] += -sPlus*(f_plus[i]-eq_plus[i]) - sMinus*(f_minus[i]-eq_minus[i]);
        cell[i+Descriptor<T>::q/2] += -sPlus*(f_plus[i]-eq_plus[i]) + sMinus*(f_minus[i]-eq_minus[i]);
    }

    if (cell.takesStatistics()) {
        gatherStatistics(statistics, rhoBar, jSqr * invRho * invRho );
    }
}

template<typename T, template<typename U> class Descriptor>
void TRTdynamics<T,Descriptor>::collideExternal (
        Cell<T,Descriptor>& cell, T rhoBar, Array<T,Descriptor<T>::d> const& j,
        T thetaBar, BlockStatistics& statistics )
{
    const T sPlus = this->getOmega();

    Array<T,Descriptor<T>::q> eq;
    // In the following, we number the plus/minus variables from 1 to (Q-1)/2.
    // So we allocate the index-zero memory location, and waste some memory
    // for convenience.
    Array<T,Descriptor<T>::q/2+1> eq_plus, eq_minus, f_plus, f_minus;

    T jSqr = normSqr(j);
    T invRho = Descriptor<T>::invRho(rhoBar);
    dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibria(rhoBar, invRho, j, jSqr, eq);

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        eq_plus[i]  = 0.5*(eq[i] + eq[i+Descriptor<T>::q/2]);
        eq_minus[i] = 0.5*(eq[i] - eq[i+Descriptor<T>::q/2]);
        f_plus[i]   = 0.5*(cell[i] + cell[i+Descriptor<T>::q/2]);
        f_minus[i]  = 0.5*(cell[i] - cell[i+Descriptor<T>::q/2]);
    }

    cell[0] += -sPlus*cell[0] + sPlus*eq[0];

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        cell[i] += -sPlus*(f_plus[i]-eq_plus[i]) - sMinus*(f_minus[i]-eq_minus[i]);
        cell[i+Descriptor<T>::q/2] += -sPlus*(f_plus[i]-eq_plus[i]) + sMinus*(f_minus[i]-eq_minus[i]);
    }

    if (cell.takesStatistics()) {
        gatherStatistics(statistics, rhoBar, jSqr * Descriptor<T>::invRho(rhoBar) * Descriptor<T>::invRho(rhoBar) );
    }
}

template<typename T, template<typename U> class Descriptor>
T TRTdynamics<T,Descriptor>::computeEquilibrium(plint iPop, T rhoBar, Array<T,Descriptor<T>::d> const& j,
                                                T jSqr, T thetaBar) const
{
    T invRho = Descriptor<T>::invRho(rhoBar);
    return dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibrium(iPop, rhoBar, invRho, j, jSqr);
}

/* *************** Class IncTRTdynamics *********************************************** */

template<typename T, template<typename U> class Descriptor>
const T IncTRTdynamics<T,Descriptor>::sMinus = 1.1;

template<typename T, template<typename U> class Descriptor>
int IncTRTdynamics<T,Descriptor>::id =
    meta::registerOneParamDynamics<T,Descriptor,IncTRTdynamics<T,Descriptor> >("IncTRT");

/** \param omega_ relaxation parameter, related to the dynamic viscosity
 */
template<typename T, template<typename U> class Descriptor>
IncTRTdynamics<T,Descriptor>::IncTRTdynamics(T omega_ )
    : IsoThermalBulkDynamics<T,Descriptor>(omega_)
{ }

template<typename T, template<typename U> class Descriptor>
IncTRTdynamics<T,Descriptor>* IncTRTdynamics<T,Descriptor>::clone() const {
    return new IncTRTdynamics<T,Descriptor>(*this);
}

template<typename T, template<typename U> class Descriptor>
int IncTRTdynamics<T,Descriptor>::getId() const {
    return id;
}

template<typename T, template<typename U> class Descriptor>
void IncTRTdynamics<T,Descriptor>::collide (
        Cell<T,Descriptor>& cell, BlockStatistics& statistics )
{
    const T sPlus = this->getOmega();

    Array<T,Descriptor<T>::q> eq;
    // In the following, we number the plus/minus variables from 1 to (Q-1)/2.
    // So we allocate the index-zero memory location, and waste some memory
    // for convenience.
    Array<T,Descriptor<T>::q/2+1> eq_plus, eq_minus, f_plus, f_minus;

    Array<T,3> j;
    T rhoBar;
    momentTemplates<T,Descriptor>::get_rhoBar_j(cell, rhoBar, j);
    T jSqr = normSqr(j);
    T invRho0 = 1.;
    dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibria(rhoBar, invRho0, j, jSqr, eq);

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        eq_plus[i]  = 0.5*(eq[i] + eq[i+Descriptor<T>::q/2]);
        eq_minus[i] = 0.5*(eq[i] - eq[i+Descriptor<T>::q/2]);
        f_plus[i]   = 0.5*(cell[i] + cell[i+Descriptor<T>::q/2]);
        f_minus[i]  = 0.5*(cell[i] - cell[i+Descriptor<T>::q/2]);
    }

    cell[0] += -sPlus*cell[0] + sPlus*eq[0];

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        cell[i] += -sPlus*(f_plus[i]-eq_plus[i]) - sMinus*(f_minus[i]-eq_minus[i]);
        cell[i+Descriptor<T>::q/2] += -sPlus*(f_plus[i]-eq_plus[i]) + sMinus*(f_minus[i]-eq_minus[i]);
    }

    if (cell.takesStatistics()) {
        gatherStatistics(statistics, rhoBar, jSqr);
    }
}

template<typename T, template<typename U> class Descriptor>
void IncTRTdynamics<T,Descriptor>::collideExternal (
        Cell<T,Descriptor>& cell, T rhoBar, Array<T,Descriptor<T>::d> const& j,
        T thetaBar, BlockStatistics& statistics )
{
    const T sPlus = this->getOmega();

    Array<T,Descriptor<T>::q> eq;
    // In the following, we number the plus/minus variables from 1 to (Q-1)/2.
    // So we allocate the index-zero memory location, and waste some memory
    // for convenience.
    Array<T,Descriptor<T>::q/2+1> eq_plus, eq_minus, f_plus, f_minus;

    T jSqr = normSqr(j);
    T invRho0 = 1.;
    dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibria(rhoBar, invRho0, j, jSqr, eq);

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        eq_plus[i]  = 0.5*(eq[i] + eq[i+Descriptor<T>::q/2]);
        eq_minus[i] = 0.5*(eq[i] - eq[i+Descriptor<T>::q/2]);
        f_plus[i]   = 0.5*(cell[i] + cell[i+Descriptor<T>::q/2]);
        f_minus[i]  = 0.5*(cell[i] - cell[i+Descriptor<T>::q/2]);
    }

    cell[0] += -sPlus*cell[0] + sPlus*eq[0];

    for (plint i=1; i<=Descriptor<T>::q/2; ++i) {
        cell[i] += -sPlus*(f_plus[i]-eq_plus[i]) - sMinus*(f_minus[i]-eq_minus[i]);
        cell[i+Descriptor<T>::q/2] += -sPlus*(f_plus[i]-eq_plus[i]) + sMinus*(f_minus[i]-eq_minus[i]);
    }

    if (cell.takesStatistics()) {
        gatherStatistics(statistics, rhoBar, jSqr);
    }
}

template<typename T, template<typename U> class Descriptor>
T IncTRTdynamics<T,Descriptor>::computeEquilibrium(plint iPop, T rhoBar, Array<T,Descriptor<T>::d> const& j,
                                                T jSqr, T thetaBar) const
{
    return dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibrium(iPop, rhoBar, (T)1, j, jSqr);
}

template<typename T, template<typename U> class Descriptor>
bool IncTRTdynamics<T,Descriptor>::velIsJ() const {
    return true;
}

template<typename T, template<typename U> class Descriptor>
void IncTRTdynamics<T,Descriptor>::computeVelocity( Cell<T,Descriptor> const& cell,
                                                                 Array<T,Descriptor<T>::d>& u ) const
{
    T dummyRhoBar;
    this->computeRhoBarJ(cell, dummyRhoBar, u);
}

}

#endif  // TRT_DYNAMICS_HH

<|endoftext|>