<commit_before>/*
Copyright (c) 2015, Dimitri Diakopoulos 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.

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 HOLDER 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 "FlacDecoder.h"
#include "FLAC/all.h"
#include "FLAC/stream_decoder.h"

#include "AudioDecoder.h"
#include <cstring>

using namespace nqr;

class FlacDecoderInternal
{

public:

    // FLAC is a big-endian format. All values are unsigned.
    FlacDecoderInternal(AudioData * d, std::string filepath) : d(d)
    {

        /////////////////////////////
        // Initialize FLAC library //
        /////////////////////////////

        decoderInternal = FLAC__stream_decoder_new();

        FLAC__stream_decoder_set_metadata_respond(decoderInternal, FLAC__METADATA_TYPE_STREAMINFO);

        //@todo: check if OGG flac
        bool initialized = FLAC__stream_decoder_init_file(decoderInternal,
                                                          filepath.c_str(),
                                                          s_writeCallback,
                                                          s_metadataCallback,
                                                          s_errorCallback,
                                                          this) == FLAC__STREAM_DECODER_INIT_STATUS_OK;

        FLAC__stream_decoder_set_md5_checking(decoderInternal, true);

        //////////////////////
        // Read Stream Data //
        /////////////////////

        if (initialized)
        {
            // Find the size and allocate memory
            FLAC__stream_decoder_process_until_end_of_metadata(decoderInternal);

            // Read memory out into our temporary internalBuffer
            FLAC__stream_decoder_process_until_end_of_stream(decoderInternal);

            // Presently unneeded, but useful for reference
            // FLAC__ChannelAssignment channelAssignment = FLAC__stream_decoder_get_channel_assignment(decoderInternal);

            // Fill out remaining user data
            d->lengthSeconds = (float) numSamples / (float) d->sampleRate;

            auto totalSamples = numSamples * d->channelCount;

            // Next, process internal buffer into the user-visible samples array
            ConvertToFloat32(d->samples.data(), internalBuffer.data(), totalSamples, d->sourceFormat);
        }

        else
        {
            throw std::runtime_error("Unable to initialize FLAC decoder");
        }

    }

    ~FlacDecoderInternal()
    {
        if (decoderInternal)
        {
            FLAC__stream_decoder_finish(decoderInternal);
            FLAC__stream_decoder_delete(decoderInternal);
        }
    }

    void processMetadata(const FLAC__StreamMetadata_StreamInfo & info)
    {
        // Currently the reference encoder and decoders only support up to 24 bits per sample.
        d->sampleRate = info.sample_rate;
        d->channelCount = info.channels; // Assert 1 to 8
        d->sourceFormat = MakeFormatForBits(info.bits_per_sample, false, true);
        d->frameSize = info.channels * info.bits_per_sample;

        const size_t bytesPerSample = GetFormatBitsPerSample(d->sourceFormat) / 8;

        numSamples = (size_t) info.total_samples;

        internalBuffer.resize(numSamples * info.channels * bytesPerSample); // as array of bytes
        d->samples.resize(numSamples * info.channels); // as audio samples in float32
    }

    ///////////////////////
    // libflac callbacks //
    ///////////////////////

    static FLAC__StreamDecoderWriteStatus s_writeCallback(const FLAC__StreamDecoder *, const FLAC__Frame* frame, const FLAC__int32 * const buffer[], void * userPtr)
    {
        FlacDecoderInternal * decoder = reinterpret_cast<FlacDecoderInternal *>(userPtr);

        const size_t bytesPerSample = GetFormatBitsPerSample(decoder->d->sourceFormat) / 8;

        auto dataPtr = decoder->internalBuffer.data();

        for (uint32_t i = 0;  i < frame->header.blocksize; i++)
        {
            for(int j = 0; j < decoder->d->channelCount; j++)
            {
                memcpy(dataPtr + decoder->bufferPosition, &buffer[j][i], bytesPerSample);
                decoder->bufferPosition += bytesPerSample;
            }
        }

        return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
    }

    static void s_metadataCallback (const FLAC__StreamDecoder *, const FLAC__StreamMetadata * metadata, void * userPtr)
    {
        static_cast<FlacDecoderInternal*>(userPtr)->processMetadata(metadata->data.stream_info);
    }

    static void s_errorCallback (const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *)
    {
        std::cerr << "FLAC Decoder Error: " << FLAC__StreamDecoderErrorStatusString[status] << std::endl;
    }

private:

    NO_COPY(FlacDecoderInternal);

    FLAC__StreamDecoder * decoderInternal;

    size_t bufferPosition = 0;
    size_t numSamples = 0;

    AudioData * d;

    std::vector<uint8_t> internalBuffer;
};

//////////////////////
// Public Interface //
//////////////////////

void FlacDecoder::LoadFromPath(AudioData * data, const std::string & path)
{
    FlacDecoderInternal decoder(data, path);
}

void FlacDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & memory)
{
    throw LoadBufferNotImplEx();
}

std::vector<std::string> FlacDecoder::GetSupportedFileExtensions()
{
    return {"flac"};
}
<commit_msg>Add flac buffer decoder<commit_after>/*
Copyright (c) 2015, Dimitri Diakopoulos 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.

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 HOLDER 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 "FlacDecoder.h"
#include "FLAC/all.h"
#include "FLAC/stream_decoder.h"

#include "AudioDecoder.h"
#include <cstring>

using namespace nqr;

class FlacDecoderInternal
{

public:

    // FLAC is a big-endian format. All values are unsigned.
    FlacDecoderInternal(AudioData * d, std::string filepath) : d(d)
    {

        /////////////////////////////
        // Initialize FLAC library //
        /////////////////////////////

        decoderInternal = FLAC__stream_decoder_new();

        FLAC__stream_decoder_set_metadata_respond(decoderInternal, FLAC__METADATA_TYPE_STREAMINFO);

        //@todo: check if OGG flac
        bool initialized = FLAC__stream_decoder_init_file(decoderInternal,
                                                          filepath.c_str(),
                                                          s_writeCallback,
                                                          s_metadataCallback,
                                                          s_errorCallback,
                                                          this) == FLAC__STREAM_DECODER_INIT_STATUS_OK;

        FLAC__stream_decoder_set_md5_checking(decoderInternal, true);

        //////////////////////
        // Read Stream Data //
        /////////////////////

        if (initialized)
        {
            // Find the size and allocate memory
            FLAC__stream_decoder_process_until_end_of_metadata(decoderInternal);

            // Read memory out into our temporary internalBuffer
            FLAC__stream_decoder_process_until_end_of_stream(decoderInternal);

            // Presently unneeded, but useful for reference
            // FLAC__ChannelAssignment channelAssignment = FLAC__stream_decoder_get_channel_assignment(decoderInternal);

            // Fill out remaining user data
            d->lengthSeconds = (float) numSamples / (float) d->sampleRate;

            auto totalSamples = numSamples * d->channelCount;

            // Next, process internal buffer into the user-visible samples array
            ConvertToFloat32(d->samples.data(), internalBuffer.data(), totalSamples, d->sourceFormat);
        }

        else
        {
            throw std::runtime_error("Unable to initialize FLAC decoder");
        }

    }

    FlacDecoderInternal(AudioData * d, const std::vector<uint8_t> & memory) : d(d), data(std::move(memory)), dataPos(0)
    {

        /////////////////////////////
        // Initialize FLAC library //
        /////////////////////////////

        decoderInternal = FLAC__stream_decoder_new();

        FLAC__stream_decoder_set_metadata_respond(decoderInternal, FLAC__METADATA_TYPE_STREAMINFO);

        bool initialized = FLAC__stream_decoder_init_stream(
          decoderInternal,
          read_callback,
          seek_callback,
          tell_callback,
          length_callback,
          eof_callback,
          s_writeCallback,
          s_metadataCallback,
          s_errorCallback,
          this
        ) == FLAC__STREAM_DECODER_INIT_STATUS_OK;

        FLAC__stream_decoder_set_md5_checking(decoderInternal, true);

        //////////////////////
        // Read Stream Data //
        /////////////////////

        if (initialized)
        {
            // Find the size and allocate memory
            FLAC__stream_decoder_process_until_end_of_metadata(decoderInternal);

            // Read memory out into our temporary internalBuffer
            FLAC__stream_decoder_process_until_end_of_stream(decoderInternal);

            // Presently unneeded, but useful for reference
            // FLAC__ChannelAssignment channelAssignment = FLAC__stream_decoder_get_channel_assignment(decoderInternal);

            // Fill out remaining user data
            d->lengthSeconds = (float) numSamples / (float) d->sampleRate;

            auto totalSamples = numSamples * d->channelCount;

            // Next, process internal buffer into the user-visible samples array
            ConvertToFloat32(d->samples.data(), internalBuffer.data(), totalSamples, d->sourceFormat);
        }

        else
        {
            throw std::runtime_error("Unable to initialize FLAC decoder");
        }

    }

    ~FlacDecoderInternal()
    {
        if (decoderInternal)
        {
            FLAC__stream_decoder_finish(decoderInternal);
            FLAC__stream_decoder_delete(decoderInternal);
        }
    }

    void processMetadata(const FLAC__StreamMetadata_StreamInfo & info)
    {
        // Currently the reference encoder and decoders only support up to 24 bits per sample.
        d->sampleRate = info.sample_rate;
        d->channelCount = info.channels; // Assert 1 to 8
        d->sourceFormat = MakeFormatForBits(info.bits_per_sample, false, true);
        d->frameSize = info.channels * info.bits_per_sample;

        const size_t bytesPerSample = GetFormatBitsPerSample(d->sourceFormat) / 8;

        numSamples = (size_t) info.total_samples;

        internalBuffer.resize(numSamples * info.channels * bytesPerSample); // as array of bytes
        d->samples.resize(numSamples * info.channels); // as audio samples in float32
    }

    ///////////////////////
    // libflac callbacks //
    ///////////////////////

    static FLAC__StreamDecoderWriteStatus s_writeCallback(const FLAC__StreamDecoder *, const FLAC__Frame* frame, const FLAC__int32 * const buffer[], void * userPtr)
    {
        FlacDecoderInternal * decoder = reinterpret_cast<FlacDecoderInternal *>(userPtr);

        const size_t bytesPerSample = GetFormatBitsPerSample(decoder->d->sourceFormat) / 8;

        auto dataPtr = decoder->internalBuffer.data();

        for (uint32_t i = 0;  i < frame->header.blocksize; i++)
        {
            for(int j = 0; j < decoder->d->channelCount; j++)
            {
                memcpy(dataPtr + decoder->bufferPosition, &buffer[j][i], bytesPerSample);
                decoder->bufferPosition += bytesPerSample;
            }
        }

        return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
    }

    static void s_metadataCallback (const FLAC__StreamDecoder *, const FLAC__StreamMetadata * metadata, void * userPtr)
    {
        static_cast<FlacDecoderInternal*>(userPtr)->processMetadata(metadata->data.stream_info);
    }

    static void s_errorCallback (const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *)
    {
        std::cerr << "FLAC Decoder Error: " << FLAC__StreamDecoderErrorStatusString[status] << std::endl;
    }

    static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) {
      FlacDecoderInternal *decoderInternal = (FlacDecoderInternal *)client_data;
      size_t readLength = std::min<size_t>(*bytes, decoderInternal->data.size() - decoderInternal->dataPos);
      if (readLength > 0) {
        memcpy(buffer, decoderInternal->data.data(), readLength);
        decoderInternal->dataPos += readLength;
        *bytes = readLength;
        if (decoderInternal->dataPos < decoderInternal->data.size()) {
          return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
        } else {
          return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
        }
      } else {
        return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
      }
    }
    static FLAC__StreamDecoderSeekStatus seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) {
      FlacDecoderInternal *decoderInternal = (FlacDecoderInternal *)client_data;
      size_t newPos = std::min<size_t>(absolute_byte_offset, decoderInternal->data.size() - decoderInternal->dataPos);
      decoderInternal->dataPos = newPos;
      return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
    }
    static FLAC__StreamDecoderTellStatus tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) {
      FlacDecoderInternal *decoderInternal = (FlacDecoderInternal *)client_data;
      *absolute_byte_offset = decoderInternal->dataPos;
      return FLAC__STREAM_DECODER_TELL_STATUS_OK;
    }
    static FLAC__StreamDecoderLengthStatus length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) {
      FlacDecoderInternal *decoderInternal = (FlacDecoderInternal *)client_data;
      *stream_length = decoderInternal->data.size();
      return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
    }
    static FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder, void *client_data) {
      FlacDecoderInternal *decoderInternal = (FlacDecoderInternal *)client_data;
      return decoderInternal->dataPos == decoderInternal->data.size();
    }

private:

    NO_COPY(FlacDecoderInternal);

    FLAC__StreamDecoder * decoderInternal;
    std::vector<uint8_t> data;
    size_t dataPos;

    size_t bufferPosition = 0;
    size_t numSamples = 0;

    AudioData * d;

    std::vector<uint8_t> internalBuffer;
};

//////////////////////
// Public Interface //
//////////////////////

void FlacDecoder::LoadFromPath(AudioData * data, const std::string & path)
{
    FlacDecoderInternal decoder(data, path);
}

void FlacDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & memory)
{
    FlacDecoderInternal decoder(data, memory);
}

std::vector<std::string> FlacDecoder::GetSupportedFileExtensions()
{
    return {"flac"};
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2006 - 2007 Volker Krause <vkrause@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 as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    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 "monitor.h"
#include "monitor_p.h"

#include "collectionlistjob.h"
#include "collectionstatusjob.h"
#include "itemfetchjob.h"
#include "notificationmanagerinterface.h"
#include "notificationmessage.h"
#include "session.h"

#include <kdebug.h>

#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnection>

#include <QtCore/QDebug>
#include <QtCore/QTimer>

using namespace Akonadi;

class Monitor::Private
{
  public:
    Private( Monitor *parent )
      : mParent( parent ),
        fetchCollection( false ),
        fetchCollectionStatus( false ),
        fetchAllParts( false )
    {
    }

    Monitor *mParent;
    org::kde::Akonadi::NotificationManager *nm;
    Collection::List collections;
    QSet<QByteArray> resources;
    QSet<int> items;
    QSet<QString> mimetypes;
    bool monitorAll;
    QList<QByteArray> sessions;
    QStringList mFetchParts;
    QHash<KJob*,NotificationMessage> pendingJobs;

    bool isCollectionMonitored( int collection, const QByteArray &resource ) const
    {
      if ( monitorAll || isCollectionMonitored( collection ) || resources.contains( resource ) )
        return true;
      return false;
    }

    bool isItemMonitored( uint item, int collection, int collectionDest,
                          const QString &mimetype, const QByteArray &resource ) const
    {
      if ( monitorAll || isCollectionMonitored( collection ) ||
           isCollectionMonitored( collectionDest ) ||items.contains( item ) ||
           resources.contains( resource ) || mimetypes.contains( mimetype ) )
        return true;
      return false;
    }

    bool isSessionIgnored( const QByteArray &sessionId ) const
    {
      return sessions.contains( sessionId );
    }

    bool connectToNotificationManager();

    // private slots
    void sessionDestroyed( QObject* );
    void slotStatusChangedFinished( KJob* );
    void slotFlushRecentlyChangedCollections();

    void slotNotify( const NotificationMessage::List &msgs );
    void slotItemJobFinished( KJob* job );
    void slotCollectionJobFinished( KJob *job );

    void emitItemNotification( const NotificationMessage &msg, const Item &item = Item(),
                               const Collection &collection = Collection(), const Collection &collectionDest = Collection() );
    void emitCollectionNotification( const NotificationMessage &msg, const Collection &col = Collection(),
                                     const Collection &par = Collection() );

    bool fetchCollection;
    bool fetchCollectionStatus;
    bool fetchAllParts;

  private:
    // collections that need a status update
    QSet<int> recentlyChangedCollections;

    bool isCollectionMonitored( int collection ) const
    {
      if ( collections.contains( Collection( collection ) ) )
        return true;
      if ( collections.contains( Collection::root() ) )
        return true;
      return false;
    }

    void fetchStatus( int colId )
    {
      CollectionStatusJob *job = new CollectionStatusJob( Collection( colId ), mParent );
      connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotStatusChangedFinished(KJob*)) );
    }

    void notifyCollectionStatusWatchers( int collection, const QByteArray &resource )
    {
      if ( isCollectionMonitored( collection, resource ) ) {
        if (recentlyChangedCollections.empty() )
          QTimer::singleShot( 500, mParent, SLOT(slotFlushRecentlyChangedCollections()) );
        recentlyChangedCollections.insert( collection );
      }
    }
};

bool Monitor::Private::connectToNotificationManager()
{
  NotificationMessage::registerDBusTypes();

  if ( !nm )
    nm = new org::kde::Akonadi::NotificationManager( QLatin1String( "org.kde.Akonadi" ),
                                                     QLatin1String( "/notifications" ),
                                                     QDBusConnection::sessionBus(), mParent );
  else
    return true;

  if ( !nm ) {
    qWarning() << "Unable to connect to notification manager";
  } else {
    connect( nm, SIGNAL(notify(Akonadi::NotificationMessage::List)),
             mParent, SLOT(slotNotify(Akonadi::NotificationMessage::List)) );
    return true;
  }
  return false;
}

void Monitor::Private::sessionDestroyed( QObject * object )
{
  Session* session = qobject_cast<Session*>( object );
  if ( session )
    sessions.removeAll( session->sessionId() );
}

void Monitor::Private::slotStatusChangedFinished( KJob* job )
{
  if ( job->error() ) {
    qWarning() << "Error on fetching collection status: " << job->errorText();
  } else {
    CollectionStatusJob *statusJob = static_cast<CollectionStatusJob*>( job );
    emit mParent->collectionStatusChanged( statusJob->collection().id(), statusJob->status() );
  }
}

void Monitor::Private::slotFlushRecentlyChangedCollections()
{
  foreach( int collection, recentlyChangedCollections ) {
    if ( fetchCollectionStatus ) {
      fetchStatus( collection );
    } else {
      static const CollectionStatus dummyStatus;
      emit mParent->collectionStatusChanged( collection, dummyStatus );
    }
  }
  recentlyChangedCollections.clear();
}

void Monitor::Private::slotNotify( const NotificationMessage::List &msgs )
{
  foreach ( const NotificationMessage msg, msgs ) {
    if ( isSessionIgnored( msg.sessionId() ) )
      continue;

    if ( msg.type() == NotificationMessage::Item ) {
      notifyCollectionStatusWatchers( msg.parentCollection(), msg.resource() );
      if ( !isItemMonitored( msg.uid(), msg.parentCollection(), msg.parentDestCollection(), msg.mimeType(), msg.resource() ) )
        continue;
      if ( !mFetchParts.isEmpty() &&
           ( msg.operation() == NotificationMessage::Add || msg.operation() == NotificationMessage::Move ) || fetchAllParts ) {
        ItemCollectionFetchJob *job = new ItemCollectionFetchJob( DataReference( msg.uid(), msg.remoteId() ),
                                                                  msg.parentCollection(), mParent );
        foreach( QString part, mFetchParts )
          job->addFetchPart( part );
        if ( fetchAllParts )
          job->fetchAllParts();
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotItemJobFinished(KJob*)) );
        continue;
      }
      if ( !mFetchParts.isEmpty() && msg.operation() == NotificationMessage::Modify ) {
        ItemFetchJob *job = new ItemFetchJob( DataReference( msg.uid(), msg.remoteId() ), mParent );
        foreach( QString part, mFetchParts )
          job->addFetchPart( part );
        if ( fetchAllParts )
          job->fetchAllParts();
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotItemJobFinished(KJob*)) );
        continue;
      }
      emitItemNotification( msg );
    } else if ( msg.type() == NotificationMessage::Collection ) {
      if ( msg.operation() != NotificationMessage::Remove && fetchCollection ) {
        Collection::List list;
        list << Collection( msg.uid() );
        if ( msg.operation() == NotificationMessage::Add )
          list << Collection( msg.parentCollection() );
        CollectionListJob *job = new CollectionListJob( list, mParent );
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotCollectionJobFinished(KJob*)) );
        continue;
      }
      if ( msg.operation() == NotificationMessage::Remove ) {
        // no need for status updates anymore
        recentlyChangedCollections.remove( msg.uid() );
      }
      emitCollectionNotification( msg );
    } else {
      qWarning() << "Received unknown change notification!";
    }
  }
}

void Monitor::Private::emitItemNotification( const NotificationMessage &msg, const Item &item,
                                             const Collection &collection, const Collection &collectionDest  )
{
  Q_ASSERT( msg.type() == NotificationMessage::Item );
  Collection col = collection;
  Collection colDest = collectionDest;
  if ( !col.isValid() ) {
    col = Collection( msg.parentCollection() );
    col.setResource( QString::fromUtf8( msg.resource() ) );
  }
  if ( !colDest.isValid() ) {
    colDest = Collection( msg.parentDestCollection() );
    // FIXME setResource here required ?
  }
  Item it = item;
  if ( !it.isValid() ) {
    it = Item( DataReference( msg.uid(), msg.remoteId() ) );
    it.setMimeType( msg.mimeType() );
  }
  switch ( msg.operation() ) {
    case NotificationMessage::Add:
      emit mParent->itemAdded( it, col );
      break;
    case NotificationMessage::Modify:
      emit mParent->itemChanged( it, msg.itemParts() );
      break;
    case NotificationMessage::Move:
      emit mParent->itemMoved( it, col, colDest );
      break;
    case NotificationMessage::Remove:
      emit mParent->itemRemoved( it.reference() );
      break;
    default:
      Q_ASSERT_X( false, "Monitor::Private::emitItemNotification()", "Invalid enum value" );
  }
}

void Monitor::Private::emitCollectionNotification( const NotificationMessage &msg, const Collection &col,
                                                   const Collection &par )
{
  Q_ASSERT( msg.type() == NotificationMessage::Collection );
  Collection collection = col;
  if ( !collection.isValid() ) {
    collection = Collection( msg.uid() );
    collection.setParent( msg.parentCollection() );
    collection.setResource( QString::fromUtf8( msg.resource() ) );
    collection.setRemoteId( msg.remoteId() );
  }
  Collection parent = par;
  if ( !parent.isValid() )
    parent = Collection( msg.parentCollection() );
  switch ( msg.operation() ) {
    case NotificationMessage::Add:
      emit mParent->collectionAdded( collection, parent );
      break;
    case NotificationMessage::Modify:
      emit mParent->collectionChanged( collection );
      break;
    case NotificationMessage::Remove:
      emit mParent->collectionRemoved( collection.id(), collection.remoteId() );
      break;
    default:
      Q_ASSERT_X( false, "Monitor::Private::emitCollectionNotification", "Invalid enum value" );
  }
}

void Monitor::Private::slotItemJobFinished( KJob* job )
{
  if ( !pendingJobs.contains( job ) ) {
    kWarning() <<"unknown job - wtf is going on here?";
    return;
  }
  NotificationMessage msg = pendingJobs.take( job );
  if ( job->error() ) {
    kWarning() <<"Error on fetching item:" << job->errorText();
  } else {
    Item item;
    Collection col;
    ItemFetchJob *fetchJob = qobject_cast<ItemFetchJob*>( job );
    if ( fetchJob && fetchJob->items().count() > 0 )
      item = fetchJob->items().first();
    ItemCollectionFetchJob *cfjob = qobject_cast<ItemCollectionFetchJob*>( job );
    if ( cfjob ) {
      item = cfjob->item();
      col = cfjob->collection();
    }
    emitItemNotification( msg, item, col );
  }
}

void Monitor::Private::slotCollectionJobFinished( KJob* job )
{
  if ( !pendingJobs.contains( job ) ) {
    kWarning() <<"unknown job - wtf is going on here?";
    return;
  }
  NotificationMessage msg = pendingJobs.take( job );
  if ( job->error() ) {
    kWarning() <<"Error on fetching collection:" << job->errorText();
  } else {
    Collection col, parent;
    CollectionListJob *listJob = qobject_cast<CollectionListJob*>( job );
    if ( listJob && listJob->collections().count() > 0 )
      col = listJob->collections().first();
    if ( listJob && listJob->collections().count() > 1 && msg.operation() == NotificationMessage::Add ) {
      parent = listJob->collections().at( 1 );
      if ( col.id() != msg.uid() )
        qSwap( col, parent );
    }
    emitCollectionNotification( msg, col, parent );
  }
}

Monitor::Monitor( QObject *parent ) :
    QObject( parent ),
    d( new Private( this ) )
{
  d->nm = 0;
  d->monitorAll = false;
  d->connectToNotificationManager();
}

Monitor::~Monitor()
{
  delete d;
}

void Monitor::monitorCollection( const Collection &collection )
{
  d->collections << collection;
}

void Monitor::monitorItem( const DataReference & ref )
{
  d->items.insert( ref.id() );
}

void Monitor::monitorResource(const QByteArray & resource)
{
  d->resources.insert( resource );
}

void Monitor::monitorMimeType(const QString & mimetype)
{
  d->mimetypes.insert( mimetype );
}

void Akonadi::Monitor::monitorAll()
{
  d->monitorAll = true;
}

void Monitor::ignoreSession(Session * session)
{
  d->sessions << session->sessionId();
}

void Monitor::fetchCollection(bool enable)
{
  d->fetchCollection = enable;
}

void Monitor::addFetchPart( const QString &identifier )
{
  if ( !d->mFetchParts.contains( identifier ) )
    d->mFetchParts.append( identifier );
}

void Monitor::fetchCollectionStatus(bool enable)
{
  d->fetchCollectionStatus = enable;
}

void Monitor::fetchAllParts()
{
  d->fetchAllParts = true;
}

#include "monitor.moc"
<commit_msg>Fix fetching of all parts of monitored items.<commit_after>/*
    Copyright (c) 2006 - 2007 Volker Krause <vkrause@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 as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    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 "monitor.h"
#include "monitor_p.h"

#include "collectionlistjob.h"
#include "collectionstatusjob.h"
#include "itemfetchjob.h"
#include "notificationmanagerinterface.h"
#include "notificationmessage.h"
#include "session.h"

#include <kdebug.h>

#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnection>

#include <QtCore/QDebug>
#include <QtCore/QTimer>

using namespace Akonadi;

class Monitor::Private
{
  public:
    Private( Monitor *parent )
      : mParent( parent ),
        fetchCollection( false ),
        fetchCollectionStatus( false ),
        fetchAllParts( false )
    {
    }

    Monitor *mParent;
    org::kde::Akonadi::NotificationManager *nm;
    Collection::List collections;
    QSet<QByteArray> resources;
    QSet<int> items;
    QSet<QString> mimetypes;
    bool monitorAll;
    QList<QByteArray> sessions;
    QStringList mFetchParts;
    QHash<KJob*,NotificationMessage> pendingJobs;

    bool isCollectionMonitored( int collection, const QByteArray &resource ) const
    {
      if ( monitorAll || isCollectionMonitored( collection ) || resources.contains( resource ) )
        return true;
      return false;
    }

    bool isItemMonitored( uint item, int collection, int collectionDest,
                          const QString &mimetype, const QByteArray &resource ) const
    {
      if ( monitorAll || isCollectionMonitored( collection ) ||
           isCollectionMonitored( collectionDest ) ||items.contains( item ) ||
           resources.contains( resource ) || mimetypes.contains( mimetype ) )
        return true;
      return false;
    }

    bool isSessionIgnored( const QByteArray &sessionId ) const
    {
      return sessions.contains( sessionId );
    }

    bool connectToNotificationManager();

    // private slots
    void sessionDestroyed( QObject* );
    void slotStatusChangedFinished( KJob* );
    void slotFlushRecentlyChangedCollections();

    void slotNotify( const NotificationMessage::List &msgs );
    void slotItemJobFinished( KJob* job );
    void slotCollectionJobFinished( KJob *job );

    void emitItemNotification( const NotificationMessage &msg, const Item &item = Item(),
                               const Collection &collection = Collection(), const Collection &collectionDest = Collection() );
    void emitCollectionNotification( const NotificationMessage &msg, const Collection &col = Collection(),
                                     const Collection &par = Collection() );

    bool fetchCollection;
    bool fetchCollectionStatus;
    bool fetchAllParts;

  private:
    // collections that need a status update
    QSet<int> recentlyChangedCollections;

    bool isCollectionMonitored( int collection ) const
    {
      if ( collections.contains( Collection( collection ) ) )
        return true;
      if ( collections.contains( Collection::root() ) )
        return true;
      return false;
    }

    void fetchStatus( int colId )
    {
      CollectionStatusJob *job = new CollectionStatusJob( Collection( colId ), mParent );
      connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotStatusChangedFinished(KJob*)) );
    }

    void notifyCollectionStatusWatchers( int collection, const QByteArray &resource )
    {
      if ( isCollectionMonitored( collection, resource ) ) {
        if (recentlyChangedCollections.empty() )
          QTimer::singleShot( 500, mParent, SLOT(slotFlushRecentlyChangedCollections()) );
        recentlyChangedCollections.insert( collection );
      }
    }
};

bool Monitor::Private::connectToNotificationManager()
{
  NotificationMessage::registerDBusTypes();

  if ( !nm )
    nm = new org::kde::Akonadi::NotificationManager( QLatin1String( "org.kde.Akonadi" ),
                                                     QLatin1String( "/notifications" ),
                                                     QDBusConnection::sessionBus(), mParent );
  else
    return true;

  if ( !nm ) {
    qWarning() << "Unable to connect to notification manager";
  } else {
    connect( nm, SIGNAL(notify(Akonadi::NotificationMessage::List)),
             mParent, SLOT(slotNotify(Akonadi::NotificationMessage::List)) );
    return true;
  }
  return false;
}

void Monitor::Private::sessionDestroyed( QObject * object )
{
  Session* session = qobject_cast<Session*>( object );
  if ( session )
    sessions.removeAll( session->sessionId() );
}

void Monitor::Private::slotStatusChangedFinished( KJob* job )
{
  if ( job->error() ) {
    qWarning() << "Error on fetching collection status: " << job->errorText();
  } else {
    CollectionStatusJob *statusJob = static_cast<CollectionStatusJob*>( job );
    emit mParent->collectionStatusChanged( statusJob->collection().id(), statusJob->status() );
  }
}

void Monitor::Private::slotFlushRecentlyChangedCollections()
{
  foreach( int collection, recentlyChangedCollections ) {
    if ( fetchCollectionStatus ) {
      fetchStatus( collection );
    } else {
      static const CollectionStatus dummyStatus;
      emit mParent->collectionStatusChanged( collection, dummyStatus );
    }
  }
  recentlyChangedCollections.clear();
}

void Monitor::Private::slotNotify( const NotificationMessage::List &msgs )
{
  foreach ( const NotificationMessage msg, msgs ) {
    if ( isSessionIgnored( msg.sessionId() ) )
      continue;

    if ( msg.type() == NotificationMessage::Item ) {
      notifyCollectionStatusWatchers( msg.parentCollection(), msg.resource() );
      if ( !isItemMonitored( msg.uid(), msg.parentCollection(), msg.parentDestCollection(), msg.mimeType(), msg.resource() ) )
        continue;
      if ( (!mFetchParts.isEmpty() || fetchAllParts) &&
           ( msg.operation() == NotificationMessage::Add || msg.operation() == NotificationMessage::Move ) ) {
        ItemCollectionFetchJob *job = new ItemCollectionFetchJob( DataReference( msg.uid(), msg.remoteId() ),
                                                                  msg.parentCollection(), mParent );
        foreach( QString part, mFetchParts )
          job->addFetchPart( part );
        if ( fetchAllParts )
          job->fetchAllParts();
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotItemJobFinished(KJob*)) );
        continue;
      }
      if ( (!mFetchParts.isEmpty() || fetchAllParts) && msg.operation() == NotificationMessage::Modify ) {
        ItemFetchJob *job = new ItemFetchJob( DataReference( msg.uid(), msg.remoteId() ), mParent );
        foreach( QString part, mFetchParts )
          job->addFetchPart( part );
        if ( fetchAllParts )
          job->fetchAllParts();
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotItemJobFinished(KJob*)) );
        continue;
      }
      emitItemNotification( msg );
    } else if ( msg.type() == NotificationMessage::Collection ) {
      if ( msg.operation() != NotificationMessage::Remove && fetchCollection ) {
        Collection::List list;
        list << Collection( msg.uid() );
        if ( msg.operation() == NotificationMessage::Add )
          list << Collection( msg.parentCollection() );
        CollectionListJob *job = new CollectionListJob( list, mParent );
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotCollectionJobFinished(KJob*)) );
        continue;
      }
      if ( msg.operation() == NotificationMessage::Remove ) {
        // no need for status updates anymore
        recentlyChangedCollections.remove( msg.uid() );
      }
      emitCollectionNotification( msg );
    } else {
      qWarning() << "Received unknown change notification!";
    }
  }
}

void Monitor::Private::emitItemNotification( const NotificationMessage &msg, const Item &item,
                                             const Collection &collection, const Collection &collectionDest  )
{
  Q_ASSERT( msg.type() == NotificationMessage::Item );
  Collection col = collection;
  Collection colDest = collectionDest;
  if ( !col.isValid() ) {
    col = Collection( msg.parentCollection() );
    col.setResource( QString::fromUtf8( msg.resource() ) );
  }
  if ( !colDest.isValid() ) {
    colDest = Collection( msg.parentDestCollection() );
    // FIXME setResource here required ?
  }
  Item it = item;
  if ( !it.isValid() ) {
    it = Item( DataReference( msg.uid(), msg.remoteId() ) );
    it.setMimeType( msg.mimeType() );
  }
  switch ( msg.operation() ) {
    case NotificationMessage::Add:
      emit mParent->itemAdded( it, col );
      break;
    case NotificationMessage::Modify:
      emit mParent->itemChanged( it, msg.itemParts() );
      break;
    case NotificationMessage::Move:
      emit mParent->itemMoved( it, col, colDest );
      break;
    case NotificationMessage::Remove:
      emit mParent->itemRemoved( it.reference() );
      break;
    default:
      Q_ASSERT_X( false, "Monitor::Private::emitItemNotification()", "Invalid enum value" );
  }
}

void Monitor::Private::emitCollectionNotification( const NotificationMessage &msg, const Collection &col,
                                                   const Collection &par )
{
  Q_ASSERT( msg.type() == NotificationMessage::Collection );
  Collection collection = col;
  if ( !collection.isValid() ) {
    collection = Collection( msg.uid() );
    collection.setParent( msg.parentCollection() );
    collection.setResource( QString::fromUtf8( msg.resource() ) );
    collection.setRemoteId( msg.remoteId() );
  }
  Collection parent = par;
  if ( !parent.isValid() )
    parent = Collection( msg.parentCollection() );
  switch ( msg.operation() ) {
    case NotificationMessage::Add:
      emit mParent->collectionAdded( collection, parent );
      break;
    case NotificationMessage::Modify:
      emit mParent->collectionChanged( collection );
      break;
    case NotificationMessage::Remove:
      emit mParent->collectionRemoved( collection.id(), collection.remoteId() );
      break;
    default:
      Q_ASSERT_X( false, "Monitor::Private::emitCollectionNotification", "Invalid enum value" );
  }
}

void Monitor::Private::slotItemJobFinished( KJob* job )
{
  if ( !pendingJobs.contains( job ) ) {
    kWarning() <<"unknown job - wtf is going on here?";
    return;
  }
  NotificationMessage msg = pendingJobs.take( job );
  if ( job->error() ) {
    kWarning() <<"Error on fetching item:" << job->errorText();
  } else {
    Item item;
    Collection col;
    ItemFetchJob *fetchJob = qobject_cast<ItemFetchJob*>( job );
    if ( fetchJob && fetchJob->items().count() > 0 )
      item = fetchJob->items().first();
    ItemCollectionFetchJob *cfjob = qobject_cast<ItemCollectionFetchJob*>( job );
    if ( cfjob ) {
      item = cfjob->item();
      col = cfjob->collection();
    }
    emitItemNotification( msg, item, col );
  }
}

void Monitor::Private::slotCollectionJobFinished( KJob* job )
{
  if ( !pendingJobs.contains( job ) ) {
    kWarning() <<"unknown job - wtf is going on here?";
    return;
  }
  NotificationMessage msg = pendingJobs.take( job );
  if ( job->error() ) {
    kWarning() <<"Error on fetching collection:" << job->errorText();
  } else {
    Collection col, parent;
    CollectionListJob *listJob = qobject_cast<CollectionListJob*>( job );
    if ( listJob && listJob->collections().count() > 0 )
      col = listJob->collections().first();
    if ( listJob && listJob->collections().count() > 1 && msg.operation() == NotificationMessage::Add ) {
      parent = listJob->collections().at( 1 );
      if ( col.id() != msg.uid() )
        qSwap( col, parent );
    }
    emitCollectionNotification( msg, col, parent );
  }
}

Monitor::Monitor( QObject *parent ) :
    QObject( parent ),
    d( new Private( this ) )
{
  d->nm = 0;
  d->monitorAll = false;
  d->connectToNotificationManager();
}

Monitor::~Monitor()
{
  delete d;
}

void Monitor::monitorCollection( const Collection &collection )
{
  d->collections << collection;
}

void Monitor::monitorItem( const DataReference & ref )
{
  d->items.insert( ref.id() );
}

void Monitor::monitorResource(const QByteArray & resource)
{
  d->resources.insert( resource );
}

void Monitor::monitorMimeType(const QString & mimetype)
{
  d->mimetypes.insert( mimetype );
}

void Akonadi::Monitor::monitorAll()
{
  d->monitorAll = true;
}

void Monitor::ignoreSession(Session * session)
{
  d->sessions << session->sessionId();
}

void Monitor::fetchCollection(bool enable)
{
  d->fetchCollection = enable;
}

void Monitor::addFetchPart( const QString &identifier )
{
  if ( !d->mFetchParts.contains( identifier ) )
    d->mFetchParts.append( identifier );
}

void Monitor::fetchCollectionStatus(bool enable)
{
  d->fetchCollectionStatus = enable;
}

void Monitor::fetchAllParts()
{
  d->fetchAllParts = true;
}

#include "monitor.moc"
<|endoftext|>


<commit_before>/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* 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 "GetUserMedia.h"
#include "Observers.h"

using namespace v8;
using namespace WebRTC;

void GetUserMedia::Init(v8::Handle<v8::Object> exports) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  exports->Set(String::NewFromUtf8(isolate, "getUserMedia"), FunctionTemplate::New(isolate, GetUserMedia::OpenMedia)->GetFunction());
}

void GetUserMedia::OpenMedia(const FunctionCallbackInfo<Value> &args) {
  Isolate* isolate = args.GetIsolate();
  HandleScope scope(isolate);

  Local<Object> constraints;  // TODO(): Required? -> Throw Error
  Local<Function> onsuccess;  // TODO(): Required? -> Throw Error
  Local<Function> onerror;    // TODO(): Required? -> Throw Error

  bool echo = true;

  uint32_t min_width = 320;
  uint32_t max_width = 1280;

  uint32_t min_height = 180;
  uint32_t max_height = 720;

  double min_fps = 24.0;
  double max_fps = 60.0;

  double min_aspectRatio = 1.33333333333; //  4/3
  double max_aspectRatio = 1.7777777778;  //  16/9

  std::string audioId;
  std::string videoId;

  if (args.Length() >= 1 && args[0]->IsObject()) {
    constraints = Local<Object>::Cast(args[0]);

    if (args.Length() >= 2 && args[1]->IsFunction()) {
      onsuccess = Local<Function>::Cast(args[1]);
    }

    if (args.Length() == 3 && args[2]->IsFunction()) {
      onerror = Local<Function>::Cast(args[2]);
    }
  }

  if (!constraints.IsEmpty()) {
    Local<Value> audio_value = constraints->Get(String::NewFromUtf8(isolate, "audio"));
    Local<Value> video_value = constraints->Get(String::NewFromUtf8(isolate, "video"));

    if (!audio_value.IsEmpty() && audio_value->IsObject()) {
      Local<Object> audio_obj = Local<Object>::Cast(audio_value);

    }

    if (!video_value.IsEmpty() && video_value->IsObject()) {
      Local<Object> video_obj = Local<Object>::Cast(video_value);

    }
  }

  // TODO(): Implement This
}
<commit_msg>Update GetUserMedia<commit_after>/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* 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 "GetUserMedia.h"
#include "Observers.h"

using namespace v8;
using namespace WebRTC;

void GetUserMedia::Init(v8::Handle<v8::Object> exports) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  exports->Set(String::NewFromUtf8(isolate, "getUserMedia"), FunctionTemplate::New(isolate, GetUserMedia::OpenMedia)->GetFunction());
}

void GetUserMedia::OpenMedia(const FunctionCallbackInfo<Value> &args) {
  Isolate* isolate = args.GetIsolate();
  HandleScope scope(isolate);

  Local<Object> constraints;  // TODO(): Required? -> IsEmpty() -> Throw Error
  Local<Function> onsuccess;  // TODO(): Required? -> IsEmpty() -> Throw Error
  Local<Function> onerror;    // TODO(): Required? -> IsEmpty() -> Throw Error

  const char *error = 0;
  bool use_audio = false;
  bool use_video = false;
  bool echo = true;

  uint32_t min_width = 320;
  uint32_t max_width = 1280;

  uint32_t min_height = 180;
  uint32_t max_height = 720;

  double min_fps = 24.0;
  double max_fps = 60.0;

  double min_aspectRatio = 1.33333333333; //  4/3
  double max_aspectRatio = 1.7777777778;  //  16/9

  std::string audioId;
  std::string videoId;

  if (args.Length() >= 1 && args[0]->IsObject()) {
    constraints = Local<Object>::Cast(args[0]);

    if (args.Length() >= 2 && args[1]->IsFunction()) {
      onsuccess = Local<Function>::Cast(args[1]);
    }

    if (args.Length() == 3 && args[2]->IsFunction()) {
      onerror = Local<Function>::Cast(args[2]);
    }
  }

  if (!constraints.IsEmpty()) {
    Local<Value> audio_value = constraints->Get(String::NewFromUtf8(isolate, "audio"));
    Local<Value> video_value = constraints->Get(String::NewFromUtf8(isolate, "video"));

    if (!audio_value.IsEmpty()) {
      if (audio_value->IsObject()) {
        Local<Object> audio_obj = Local<Object>::Cast(audio_value);

        // TODO(): Walk through arguments

      } else if (audio_value->IsTrue()) {
        use_audio = true;
      }
    }

    if (!video_value.IsEmpty()) {
      if (video_value->IsObject()) {
        Local<Object> video_obj = Local<Object>::Cast(video_value);

        // TODO(): Walk through arguments

      }
      else if (video_value->IsTrue()) {
        use_video = true;
      }
    }
  }

  if (use_audio || use_video) {
    rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory = webrtc::CreatePeerConnectionFactory();

  }

  if (error) {

  } else {

  }
}
<|endoftext|>


<commit_before>#ifndef DUNE_STUFF_MATH_HH
#define DUNE_STUFF_MATH_HH

#include <vector>
#include <limits>
#include <algorithm>
#include <cstring>
#include <iostream>
#include "static_assert.hh"
#include <boost/format.hpp>
#include <boost/static_assert.hpp>
#include <boost/fusion/include/void.hpp>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/max.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/mean.hpp>

namespace Stuff {

/** \todo DOCME **/
template <class SomeRangeType, class OtherRangeType >
static double colonProduct(    const SomeRangeType& arg1,
						const OtherRangeType& arg2 )
{
	dune_static_assert( SomeRangeType::cols == SomeRangeType::rows
			&& OtherRangeType::cols == OtherRangeType::rows
			&& int(OtherRangeType::cols) == int(SomeRangeType::rows), "RangeTypes_dont_fit" );

	double ret = 0.0;
	// iterators
	typedef typename SomeRangeType::ConstRowIterator
		ConstRowIteratorType;
	typedef typename SomeRangeType::row_type::ConstIterator
		ConstIteratorType;
	ConstRowIteratorType arg1RowItEnd = arg1.end();
	ConstRowIteratorType arg2RowItEnd = arg2.end();
	ConstRowIteratorType arg2RowIt = arg2.begin();
	for (   ConstRowIteratorType arg1RowIt = arg1.begin();
			arg1RowIt != arg1RowItEnd, arg2RowIt != arg2RowItEnd;
			++arg1RowIt, ++arg2RowIt ) {
		ConstIteratorType row1ItEnd = arg1RowIt->end();
		ConstIteratorType row2ItEnd = arg2RowIt->end();
		ConstIteratorType row2It = arg2RowIt->begin();
		for (   ConstIteratorType row1It = arg1RowIt->begin();
				row1It != row1ItEnd, row2It != row2ItEnd;
				++row1It, ++row2It ) {
			ret += *row1It * *row2It;
		}
	}
	return ret;
}

/**
 *  \brief  dyadic product
 *
 *          Implements \f$\left(arg_{1} \otimes arg_{2}\right)_{i,j}:={arg_{1}}_{i} {arg_{2}}_{j}\f$
 *			RangeType1 should be fieldmatrix, RangeType2 fieldvector
 **/
template <class RangeType1, class RangeType2 >
static RangeType1 dyadicProduct(   const RangeType2& arg1,
								const RangeType2& arg2 )
{
	RangeType1 ret( 0.0 );
	typedef typename RangeType1::RowIterator
		MatrixRowIteratorType;
	typedef typename RangeType2::ConstIterator
		ConstVectorIteratorType;
	typedef typename RangeType2::Iterator
		VectorIteratorType;
	MatrixRowIteratorType rItEnd = ret.end();
	ConstVectorIteratorType arg1It = arg1.begin();
	for ( MatrixRowIteratorType rIt = ret.begin(); rIt != rItEnd; ++rIt ) {
		ConstVectorIteratorType arg2It = arg2.begin();
		VectorIteratorType vItEnd = rIt->end();
		for (   VectorIteratorType vIt = rIt->begin();
				vIt != vItEnd;
				++vIt ) {
			*vIt = *arg1It * *arg2It;
			++arg2It;
		}
		++arg1It;
	}
	return ret;
}

/** \brief a vector wrapper for continiously updating min,max,avg of some element type vector
  \todo find use? it's only used in minimal as testcase for itself...
  **/
template < class ElementType >
class MinMaxAvg {
	protected:
		typedef MinMaxAvg< ElementType >
			ThisType;
		typedef std::vector< ElementType >
			ElementsVec;
		typedef typename ElementsVec::const_iterator
			ElementsVecConstIterator;

	public:
		MinMaxAvg()
		{}

		template < class stl_container_type >
		MinMaxAvg( const stl_container_type& elements )
		{
			dune_static_assert( (boost::is_same< ElementType, typename stl_container_type::value_type >::value),
								 "cannot assign mismatching types" );
			acc_ = std::for_each( elements.begin(), elements.end(), acc_ );
		}

		ElementType min () const { return boost::accumulators::min(acc_); }
		ElementType max () const { return boost::accumulators::max(acc_); }
		ElementType average () const { return boost::accumulators::mean(acc_); }

		void push( const ElementType& el ) {
			acc_( el );
		}

		template < class Stream >
		void output( Stream& stream ) {
			stream << boost::format( "min: %e\tmax: %e\tavg: %e\n" ) % min() % max() % average();
		}

	protected:
		typedef boost::accumulators::stats<
				boost::accumulators::tag::max,
				boost::accumulators::tag::min,
				boost::accumulators::tag::mean >
			StatsType;
		boost::accumulators::accumulator_set< ElementType,StatsType > acc_;

		MinMaxAvg( const ThisType& other );
};

//! bound \param var in [\param min,\param max]
template <typename T> T clamp(const T var,const T min,const T max)
{
	return ( (var < min) ? min : ( var > max ) ? max : var );
}

//! docme
class MovingAverage
{
	double avg_;
	size_t steps_;
public:
	MovingAverage()
		:avg_(0.0),steps_(0)
	{}
	MovingAverage& operator += (double val)
	{
		avg_ += ( val - avg_ ) / ++steps_;
		return *this;
	}
	operator double () { return avg_; }
};

//! no-branch sign function
long sign(long x) { return long(x!=0) | (long(x>=0)-1);  }

} //end namespace Stuff

#endif // DUNE_STUFF_MATH_HH
<commit_msg>MinMaxAvg: deprecate push method in favor of operator()<commit_after>#ifndef DUNE_STUFF_MATH_HH
#define DUNE_STUFF_MATH_HH

#include <vector>
#include <limits>
#include <algorithm>
#include <cstring>
#include <iostream>
#include "static_assert.hh"
#include <boost/format.hpp>
#include <boost/static_assert.hpp>
#include <boost/fusion/include/void.hpp>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/max.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/mean.hpp>

#include <dune/common/deprecated.hh>

namespace Stuff {

/** \todo DOCME **/
template <class SomeRangeType, class OtherRangeType >
static double colonProduct(    const SomeRangeType& arg1,
						const OtherRangeType& arg2 )
{
	dune_static_assert( SomeRangeType::cols == SomeRangeType::rows
			&& OtherRangeType::cols == OtherRangeType::rows
			&& int(OtherRangeType::cols) == int(SomeRangeType::rows), "RangeTypes_dont_fit" );

	double ret = 0.0;
	// iterators
	typedef typename SomeRangeType::ConstRowIterator
		ConstRowIteratorType;
	typedef typename SomeRangeType::row_type::ConstIterator
		ConstIteratorType;
	ConstRowIteratorType arg1RowItEnd = arg1.end();
	ConstRowIteratorType arg2RowItEnd = arg2.end();
	ConstRowIteratorType arg2RowIt = arg2.begin();
	for (   ConstRowIteratorType arg1RowIt = arg1.begin();
			arg1RowIt != arg1RowItEnd, arg2RowIt != arg2RowItEnd;
			++arg1RowIt, ++arg2RowIt ) {
		ConstIteratorType row1ItEnd = arg1RowIt->end();
		ConstIteratorType row2ItEnd = arg2RowIt->end();
		ConstIteratorType row2It = arg2RowIt->begin();
		for (   ConstIteratorType row1It = arg1RowIt->begin();
				row1It != row1ItEnd, row2It != row2ItEnd;
				++row1It, ++row2It ) {
			ret += *row1It * *row2It;
		}
	}
	return ret;
}

/**
 *  \brief  dyadic product
 *
 *          Implements \f$\left(arg_{1} \otimes arg_{2}\right)_{i,j}:={arg_{1}}_{i} {arg_{2}}_{j}\f$
 *			RangeType1 should be fieldmatrix, RangeType2 fieldvector
 **/
template <class RangeType1, class RangeType2 >
static RangeType1 dyadicProduct(   const RangeType2& arg1,
								const RangeType2& arg2 )
{
	RangeType1 ret( 0.0 );
	typedef typename RangeType1::RowIterator
		MatrixRowIteratorType;
	typedef typename RangeType2::ConstIterator
		ConstVectorIteratorType;
	typedef typename RangeType2::Iterator
		VectorIteratorType;
	MatrixRowIteratorType rItEnd = ret.end();
	ConstVectorIteratorType arg1It = arg1.begin();
	for ( MatrixRowIteratorType rIt = ret.begin(); rIt != rItEnd; ++rIt ) {
		ConstVectorIteratorType arg2It = arg2.begin();
		VectorIteratorType vItEnd = rIt->end();
		for (   VectorIteratorType vIt = rIt->begin();
				vIt != vItEnd;
				++vIt ) {
			*vIt = *arg1It * *arg2It;
			++arg2It;
		}
		++arg1It;
	}
	return ret;
}

/** \brief a vector wrapper for continiously updating min,max,avg of some element type vector
  \todo find use? it's only used in minimal as testcase for itself...
  **/
template < class ElementType >
class MinMaxAvg {
	protected:
		typedef MinMaxAvg< ElementType >
			ThisType;
		typedef std::vector< ElementType >
			ElementsVec;
		typedef typename ElementsVec::const_iterator
			ElementsVecConstIterator;

	public:
		MinMaxAvg()
		{}

		template < class stl_container_type >
		MinMaxAvg( const stl_container_type& elements )
		{
			dune_static_assert( (boost::is_same< ElementType, typename stl_container_type::value_type >::value),
								 "cannot assign mismatching types" );
			acc_ = std::for_each( elements.begin(), elements.end(), acc_ );
		}

		ElementType min () const { return boost::accumulators::min(acc_); }
		ElementType max () const { return boost::accumulators::max(acc_); }
		ElementType average () const { return boost::accumulators::mean(acc_); }

		void DUNE_DEPRECATED push( const ElementType& el ) {
			acc_( el );
		}

		void operator()( const ElementType& el ) {
			acc_( el );
		}

		template < class Stream >
		void output( Stream& stream ) {
			stream << boost::format( "min: %e\tmax: %e\tavg: %e\n" ) % min() % max() % average();
		}

	protected:
		typedef boost::accumulators::stats<
				boost::accumulators::tag::max,
				boost::accumulators::tag::min,
				boost::accumulators::tag::mean >
			StatsType;
		boost::accumulators::accumulator_set< ElementType,StatsType > acc_;

		MinMaxAvg( const ThisType& other );
};

//! bound \param var in [\param min,\param max]
template <typename T> T clamp(const T var,const T min,const T max)
{
	return ( (var < min) ? min : ( var > max ) ? max : var );
}

//! docme
class MovingAverage
{
	double avg_;
	size_t steps_;
public:
	MovingAverage()
		:avg_(0.0),steps_(0)
	{}
	MovingAverage& operator += (double val)
	{
		avg_ += ( val - avg_ ) / ++steps_;
		return *this;
	}
	operator double () { return avg_; }
};

//! no-branch sign function
long sign(long x) { return long(x!=0) | (long(x>=0)-1);  }

} //end namespace Stuff

#endif // DUNE_STUFF_MATH_HH
<|endoftext|>


<commit_before>#ifndef AMGCL_ADAPTER_BLOCK_MATRIX_HPP
#define AMGCL_ADAPTER_BLOCK_MATRIX_HPP

/*
The MIT License

Copyright (c) 2012-2016 Denis Demidov <dennis.demidov@gmail.com>

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.
*/

/**
\file    amgcl/adapter/block_matrix.hpp
\author  Denis Demidov <dennis.demidov@gmail.com>
\brief   On-the-fly conversion to block valued matrix.
\ingroup adapters
*/

#include <amgcl/util.hpp>
#include <amgcl/backend/detail/matrix_ops.hpp>

namespace amgcl {
namespace adapter {

template <class Matrix, int BlockSize, class BlockType>
struct block_matrix_adapter {
    typedef BlockType val_type;

    const Matrix &A;

    block_matrix_adapter(const Matrix &A) : A(A) {
        precondition(
                backend::rows(A) % BlockSize == 0 &&
                backend::cols(A) % BlockSize == 0,
                "Matrix size is not divisible by block size!"
                );
    }

    size_t rows() const {
        return backend::rows(A) / BlockSize;
    }

    size_t cols() const {
        return backend::cols(A) / BlockSize;
    }

    size_t nonzeros() const {
        // Just an estimate:
        return backend::nonzeros(A) / (BlockSize * BlockSize);
    }

    struct row_iterator {
        typedef typename backend::row_iterator<Matrix>::type Base;
        typedef ptrdiff_t col_type;
        typedef BlockType val_type;

        boost::array<boost::shared_ptr<Base>, BlockSize> base;

        row_iterator(const Matrix &A, col_type row) {
            for(int i = 0; i < BlockSize; ++i)
                base[i] = boost::make_shared<Base>(backend::row_begin(A, row * BlockSize + i));
        }

        operator bool() const {
            for(int i = 0; i < BlockSize; ++i)
                if (*base[i]) return true;
            return false;
        }

        row_iterator& operator++() {
            col_type cur_col = col();

            for(int i = 0; i < BlockSize; ++i) {
                while (*base[i] && base[i]->col() / BlockSize == cur_col) {
                    ++(*base[i]);
                }
            }

            return *this;
        }

        col_type col() const {
            col_type cur_col = 0;
            bool first = true;
            for(int i = 0; i < BlockSize; ++i) {
                if (*base[i]) {
                    if (first) {
                        cur_col = base[i]->col() / BlockSize;
                        first = false;
                    } else {
                        cur_col = std::min<col_type>(cur_col, base[i]->col() / BlockSize);
                    }
                }
            }
            return cur_col;
        }

        val_type value() const {
            col_type cur_col = col();
            val_type val = math::zero<val_type>();

            for(int i = 0; i < BlockSize; ++i) {
                for(Base a = *base[i]; a && a.col() / BlockSize == cur_col; ++a) {
                    val(i,a.col() % BlockSize) = a.value();
                }
            }

            return val;
        }
    };

    row_iterator row_begin(size_t i) const {
        return row_iterator(A, i);
    }
};

/// Convert scalar-valued matrix to a block-valued one.
template <int BlockSize, class BlockType, class Matrix>
block_matrix_adapter<Matrix, BlockSize, BlockType> block_matrix(const Matrix &A) {
    return block_matrix_adapter<Matrix, BlockSize, BlockType>(A);
}

} // namespace adapter

namespace backend {

//---------------------------------------------------------------------------
// Specialization of matrix interface
//---------------------------------------------------------------------------
template <class Matrix, int BlockSize, class BlockType>
struct value_type< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    typedef BlockType type;
};

template <class Matrix, int BlockSize, class BlockType>
struct rows_impl< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    static size_t get(const adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> &A) {
        return A.rows();
    }
};

template <class Matrix, int BlockSize, class BlockType>
struct cols_impl< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    static size_t get(const adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> &A) {
        return A.cols();
    }
};

template <class Matrix, int BlockSize, class BlockType>
struct nonzeros_impl< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    static size_t get(const adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> &A) {
        return A.nonzeros();
    }
};

template <class Matrix, int BlockSize, class BlockType>
struct row_iterator< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    typedef
        typename adapter::block_matrix_adapter<Matrix, BlockSize, BlockType>::row_iterator
        type;
};

template <class Matrix, int BlockSize, class BlockType>
struct row_begin_impl< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    typedef adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> BM;
    static typename row_iterator<BM>::type
    get(const BM &matrix, size_t row) {
        return matrix.row_begin(row);
    }
};

namespace detail {

template <class Matrix, int BlockSize, class BlockType>
struct use_builtin_matrix_ops< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
    : boost::true_type
{};

} // namespace detail
} // namespace backend
} // namespace amgcl

#endif
<commit_msg>Get rid of indirection in block matrix iterator<commit_after>#ifndef AMGCL_ADAPTER_BLOCK_MATRIX_HPP
#define AMGCL_ADAPTER_BLOCK_MATRIX_HPP

/*
The MIT License

Copyright (c) 2012-2016 Denis Demidov <dennis.demidov@gmail.com>

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.
*/

/**
\file    amgcl/adapter/block_matrix.hpp
\author  Denis Demidov <dennis.demidov@gmail.com>
\brief   On-the-fly conversion to block valued matrix.
\ingroup adapters
*/

#include <boost/container/static_vector.hpp>

#include <amgcl/util.hpp>
#include <amgcl/backend/detail/matrix_ops.hpp>

namespace amgcl {
namespace adapter {

template <class Matrix, int BlockSize, class BlockType>
struct block_matrix_adapter {
    typedef BlockType val_type;

    const Matrix &A;

    block_matrix_adapter(const Matrix &A) : A(A) {
        precondition(
                backend::rows(A) % BlockSize == 0 &&
                backend::cols(A) % BlockSize == 0,
                "Matrix size is not divisible by block size!"
                );
    }

    size_t rows() const {
        return backend::rows(A) / BlockSize;
    }

    size_t cols() const {
        return backend::cols(A) / BlockSize;
    }

    size_t nonzeros() const {
        // Just an estimate:
        return backend::nonzeros(A) / (BlockSize * BlockSize);
    }

    struct row_iterator {
        typedef typename backend::row_iterator<Matrix>::type Base;
        typedef ptrdiff_t col_type;
        typedef BlockType val_type;

        boost::container::static_vector<Base, BlockSize> base;

        row_iterator(const Matrix &A, col_type row) {
            for(int i = 0; i < BlockSize; ++i)
                base.push_back(backend::row_begin(A, row * BlockSize + i));
        }

        operator bool() const {
            for(int i = 0; i < BlockSize; ++i)
                if (base[i]) return true;
            return false;
        }

        row_iterator& operator++() {
            col_type cur_col = col();

            for(int i = 0; i < BlockSize; ++i) {
                while (base[i] && base[i].col() / BlockSize == cur_col) {
                    ++base[i];
                }
            }

            return *this;
        }

        col_type col() const {
            col_type cur_col = 0;
            bool first = true;
            for(int i = 0; i < BlockSize; ++i) {
                if (base[i]) {
                    if (first) {
                        cur_col = base[i].col() / BlockSize;
                        first = false;
                    } else {
                        cur_col = std::min<col_type>(cur_col, base[i].col() / BlockSize);
                    }
                }
            }
            return cur_col;
        }

        val_type value() const {
            col_type cur_col = col();
            val_type val = math::zero<val_type>();

            for(int i = 0; i < BlockSize; ++i) {
                for(Base a = base[i]; a && a.col() / BlockSize == cur_col; ++a) {
                    val(i, a.col() % BlockSize) = a.value();
                }
            }

            return val;
        }
    };

    row_iterator row_begin(size_t i) const {
        return row_iterator(A, i);
    }
};

/// Convert scalar-valued matrix to a block-valued one.
template <int BlockSize, class BlockType, class Matrix>
block_matrix_adapter<Matrix, BlockSize, BlockType> block_matrix(const Matrix &A) {
    return block_matrix_adapter<Matrix, BlockSize, BlockType>(A);
}

} // namespace adapter

namespace backend {

//---------------------------------------------------------------------------
// Specialization of matrix interface
//---------------------------------------------------------------------------
template <class Matrix, int BlockSize, class BlockType>
struct value_type< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    typedef BlockType type;
};

template <class Matrix, int BlockSize, class BlockType>
struct rows_impl< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    static size_t get(const adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> &A) {
        return A.rows();
    }
};

template <class Matrix, int BlockSize, class BlockType>
struct cols_impl< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    static size_t get(const adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> &A) {
        return A.cols();
    }
};

template <class Matrix, int BlockSize, class BlockType>
struct nonzeros_impl< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    static size_t get(const adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> &A) {
        return A.nonzeros();
    }
};

template <class Matrix, int BlockSize, class BlockType>
struct row_iterator< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    typedef
        typename adapter::block_matrix_adapter<Matrix, BlockSize, BlockType>::row_iterator
        type;
};

template <class Matrix, int BlockSize, class BlockType>
struct row_begin_impl< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
{
    typedef adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> BM;
    static typename row_iterator<BM>::type
    get(const BM &matrix, size_t row) {
        return matrix.row_begin(row);
    }
};

namespace detail {

template <class Matrix, int BlockSize, class BlockType>
struct use_builtin_matrix_ops< adapter::block_matrix_adapter<Matrix, BlockSize, BlockType> >
    : boost::true_type
{};

} // namespace detail
} // namespace backend
} // namespace amgcl

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/bookmarks/bookmark_utils.h"

#include "apps/app_launcher.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/search.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/simple_message_box.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/web_contents.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/net_util.h"
#include "ui/base/l10n/l10n_util.h"

namespace chrome {

int num_bookmark_urls_before_prompting = 15;

namespace {

// Iterator that iterates through a set of BookmarkNodes returning the URLs
// for nodes that are urls, or the URLs for the children of non-url urls.
// This does not recurse through all descendants, only immediate children.
// The following illustrates
// typical usage:
// OpenURLIterator iterator(nodes);
// while (iterator.has_next()) {
//   const GURL* url = iterator.NextURL();
//   // do something with |urll|.
// }
class OpenURLIterator {
 public:
  explicit OpenURLIterator(const std::vector<const BookmarkNode*>& nodes)
      : child_index_(0),
        next_(NULL),
        parent_(nodes.begin()),
        end_(nodes.end()) {
    FindNext();
  }

  bool has_next() { return next_ != NULL;}

  const GURL* NextURL() {
    if (!has_next()) {
      NOTREACHED();
      return NULL;
    }

    const GURL* next = next_;
    FindNext();
    return next;
  }

 private:
  // Seach next node which has URL.
  void FindNext() {
    for (; parent_ < end_; ++parent_, child_index_ = 0) {
      if ((*parent_)->is_url()) {
        next_ = &(*parent_)->url();
        ++parent_;
        child_index_ = 0;
        return;
      } else {
        for (; child_index_ < (*parent_)->child_count(); ++child_index_) {
          const BookmarkNode* child = (*parent_)->GetChild(child_index_);
          if (child->is_url()) {
            next_ = &child->url();
            ++child_index_;
            return;
          }
        }
      }
    }
    next_ = NULL;
  }

  int child_index_;
  const GURL* next_;
  std::vector<const BookmarkNode*>::const_iterator parent_;
  const std::vector<const BookmarkNode*>::const_iterator end_;

  DISALLOW_COPY_AND_ASSIGN(OpenURLIterator);
};

bool ShouldOpenAll(gfx::NativeWindow parent,
                   const std::vector<const BookmarkNode*>& nodes) {
  int child_count = 0;
  OpenURLIterator iterator(nodes);
  while (iterator.has_next()) {
    iterator.NextURL();
    child_count++;
  }

  if (child_count < num_bookmark_urls_before_prompting)
    return true;

  return ShowMessageBox(parent,
      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
      l10n_util::GetStringFUTF16(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL,
                                 base::IntToString16(child_count)),
      MESSAGE_BOX_TYPE_QUESTION) == MESSAGE_BOX_RESULT_YES;
}

// Returns the total number of descendants nodes.
int ChildURLCountTotal(const BookmarkNode* node) {
  int result = 0;
  for (int i = 0; i < node->child_count(); ++i) {
    const BookmarkNode* child = node->GetChild(i);
    result++;
    if (child->is_folder())
      result += ChildURLCountTotal(child);
  }
  return result;
}

// Returns in |urls|, the url and title pairs for each open tab in browser.
void GetURLsForOpenTabs(Browser* browser,
                        std::vector<std::pair<GURL, string16> >* urls) {
  for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
    std::pair<GURL, string16> entry;
    GetURLAndTitleToBookmark(browser->tab_strip_model()->GetWebContentsAt(i),
                             &(entry.first), &(entry.second));
    urls->push_back(entry);
  }
}

}  // namespace

void OpenAll(gfx::NativeWindow parent,
             content::PageNavigator* navigator,
             const std::vector<const BookmarkNode*>& nodes,
             WindowOpenDisposition initial_disposition,
             content::BrowserContext* browser_context) {
  if (!ShouldOpenAll(parent, nodes))
    return;

  // Opens all |nodes| of type URL and any children of |nodes| that are of type
  // URL. |navigator| is the PageNavigator used to open URLs. After the first
  // url is opened |opened_first_url| is set to true and |navigator| is set to
  // the PageNavigator of the last active tab. This is done to handle a window
  // disposition of new window, in which case we want subsequent tabs to open in
  // that window.
  bool opened_first_url = false;
  WindowOpenDisposition disposition = initial_disposition;
  OpenURLIterator iterator(nodes);
  while (iterator.has_next()) {
    const GURL* url = iterator.NextURL();
    // When |initial_disposition| is OFF_THE_RECORD, a node which can't be
    // opened in incognito window, it is detected using |browser_context|, is
    // not opened.
    if (initial_disposition == OFF_THE_RECORD &&
        !IsURLAllowedInIncognito(*url, browser_context))
      continue;

    content::WebContents* opened_tab = navigator->OpenURL(
        content::OpenURLParams(*url, content::Referrer(), disposition,
                               content::PAGE_TRANSITION_AUTO_BOOKMARK, false));

    if (!opened_first_url) {
      opened_first_url = true;
      disposition = NEW_BACKGROUND_TAB;
      // We opened the first URL which may have opened a new window or clobbered
      // the current page, reset the navigator just to be sure. |opened_tab| may
      // be NULL in tests.
      if (opened_tab)
        navigator = opened_tab;
    }
  }
}

void OpenAll(gfx::NativeWindow parent,
             content::PageNavigator* navigator,
             const BookmarkNode* node,
             WindowOpenDisposition initial_disposition,
             content::BrowserContext* browser_context) {
  std::vector<const BookmarkNode*> nodes;
  nodes.push_back(node);
  OpenAll(parent, navigator, nodes, initial_disposition, browser_context);
}

bool ConfirmDeleteBookmarkNode(const BookmarkNode* node,
                               gfx::NativeWindow window) {
  DCHECK(node && node->is_folder() && !node->empty());
  return ShowMessageBox(window,
      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
      l10n_util::GetStringFUTF16Int(IDS_BOOKMARK_EDITOR_CONFIRM_DELETE,
                                    ChildURLCountTotal(node)),
      MESSAGE_BOX_TYPE_QUESTION) == MESSAGE_BOX_RESULT_YES;
}

void ShowBookmarkAllTabsDialog(Browser* browser) {
  Profile* profile = browser->profile();
  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile);
  DCHECK(model && model->IsLoaded());

  const BookmarkNode* parent = model->GetParentForNewNodes();
  BookmarkEditor::EditDetails details =
      BookmarkEditor::EditDetails::AddFolder(parent, parent->child_count());
  GetURLsForOpenTabs(browser, &(details.urls));
  DCHECK(!details.urls.empty());

  BookmarkEditor::Show(browser->window()->GetNativeWindow(), profile, details,
                       BookmarkEditor::SHOW_TREE);
}

bool HasBookmarkURLs(const std::vector<const BookmarkNode*>& selection) {
  OpenURLIterator iterator(selection);
  return iterator.has_next();
}

bool HasBookmarkURLsAllowedInIncognitoMode(
    const std::vector<const BookmarkNode*>& selection,
    content::BrowserContext* browser_context) {
  OpenURLIterator iterator(selection);
  while (iterator.has_next()) {
    const GURL* url = iterator.NextURL();
    if (IsURLAllowedInIncognito(*url, browser_context))
      return true;
  }
  return false;
}

void GetURLAndTitleToBookmark(content::WebContents* web_contents,
                              GURL* url,
                              string16* title) {
  *url = web_contents->GetURL();
  *title = web_contents->GetTitle();
}

void ToggleBookmarkBarWhenVisible(content::BrowserContext* browser_context) {
  PrefService* prefs = components::UserPrefs::Get(browser_context);
  const bool always_show = !prefs->GetBoolean(prefs::kShowBookmarkBar);

  // The user changed when the bookmark bar is shown, update the preferences.
  prefs->SetBoolean(prefs::kShowBookmarkBar, always_show);
}

string16 FormatBookmarkURLForDisplay(const GURL& url,
                                     const PrefService* prefs) {
  std::string languages;
  if (prefs)
    languages = prefs->GetString(prefs::kAcceptLanguages);

  // Because this gets re-parsed by FixupURL(), it's safe to omit the scheme
  // and trailing slash, and unescape most characters.  However, it's
  // important not to drop any username/password, or unescape anything that
  // changes the URL's meaning.
  return net::FormatUrl(
      url, languages,
      net::kFormatUrlOmitAll & ~net::kFormatUrlOmitUsernamePassword,
      net::UnescapeRule::SPACES, NULL, NULL, NULL);
}

bool IsAppsShortcutEnabled(const Profile* profile) {
  return chrome::IsInstantExtendedAPIEnabled() &&
      !apps::WasAppLauncherEnabled() &&
      !profile->IsOffTheRecord();
}

bool ShouldShowAppsShortcutInBookmarkBar(Profile* profile) {
  return IsAppsShortcutEnabled(profile) &&
      profile->GetPrefs()->GetBoolean(prefs::kShowAppsShortcutInBookmarkBar);
}

}  // namespace chrome
<commit_msg>Apps bookmark should remain when App Launcher is installed on non-Ash platforms.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/bookmarks/bookmark_utils.h"

#include "apps/app_launcher.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/search.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/simple_message_box.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/web_contents.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/net_util.h"
#include "ui/base/l10n/l10n_util.h"

namespace chrome {

int num_bookmark_urls_before_prompting = 15;

namespace {

// Iterator that iterates through a set of BookmarkNodes returning the URLs
// for nodes that are urls, or the URLs for the children of non-url urls.
// This does not recurse through all descendants, only immediate children.
// The following illustrates
// typical usage:
// OpenURLIterator iterator(nodes);
// while (iterator.has_next()) {
//   const GURL* url = iterator.NextURL();
//   // do something with |urll|.
// }
class OpenURLIterator {
 public:
  explicit OpenURLIterator(const std::vector<const BookmarkNode*>& nodes)
      : child_index_(0),
        next_(NULL),
        parent_(nodes.begin()),
        end_(nodes.end()) {
    FindNext();
  }

  bool has_next() { return next_ != NULL;}

  const GURL* NextURL() {
    if (!has_next()) {
      NOTREACHED();
      return NULL;
    }

    const GURL* next = next_;
    FindNext();
    return next;
  }

 private:
  // Seach next node which has URL.
  void FindNext() {
    for (; parent_ < end_; ++parent_, child_index_ = 0) {
      if ((*parent_)->is_url()) {
        next_ = &(*parent_)->url();
        ++parent_;
        child_index_ = 0;
        return;
      } else {
        for (; child_index_ < (*parent_)->child_count(); ++child_index_) {
          const BookmarkNode* child = (*parent_)->GetChild(child_index_);
          if (child->is_url()) {
            next_ = &child->url();
            ++child_index_;
            return;
          }
        }
      }
    }
    next_ = NULL;
  }

  int child_index_;
  const GURL* next_;
  std::vector<const BookmarkNode*>::const_iterator parent_;
  const std::vector<const BookmarkNode*>::const_iterator end_;

  DISALLOW_COPY_AND_ASSIGN(OpenURLIterator);
};

bool ShouldOpenAll(gfx::NativeWindow parent,
                   const std::vector<const BookmarkNode*>& nodes) {
  int child_count = 0;
  OpenURLIterator iterator(nodes);
  while (iterator.has_next()) {
    iterator.NextURL();
    child_count++;
  }

  if (child_count < num_bookmark_urls_before_prompting)
    return true;

  return ShowMessageBox(parent,
      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
      l10n_util::GetStringFUTF16(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL,
                                 base::IntToString16(child_count)),
      MESSAGE_BOX_TYPE_QUESTION) == MESSAGE_BOX_RESULT_YES;
}

// Returns the total number of descendants nodes.
int ChildURLCountTotal(const BookmarkNode* node) {
  int result = 0;
  for (int i = 0; i < node->child_count(); ++i) {
    const BookmarkNode* child = node->GetChild(i);
    result++;
    if (child->is_folder())
      result += ChildURLCountTotal(child);
  }
  return result;
}

// Returns in |urls|, the url and title pairs for each open tab in browser.
void GetURLsForOpenTabs(Browser* browser,
                        std::vector<std::pair<GURL, string16> >* urls) {
  for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
    std::pair<GURL, string16> entry;
    GetURLAndTitleToBookmark(browser->tab_strip_model()->GetWebContentsAt(i),
                             &(entry.first), &(entry.second));
    urls->push_back(entry);
  }
}

}  // namespace

void OpenAll(gfx::NativeWindow parent,
             content::PageNavigator* navigator,
             const std::vector<const BookmarkNode*>& nodes,
             WindowOpenDisposition initial_disposition,
             content::BrowserContext* browser_context) {
  if (!ShouldOpenAll(parent, nodes))
    return;

  // Opens all |nodes| of type URL and any children of |nodes| that are of type
  // URL. |navigator| is the PageNavigator used to open URLs. After the first
  // url is opened |opened_first_url| is set to true and |navigator| is set to
  // the PageNavigator of the last active tab. This is done to handle a window
  // disposition of new window, in which case we want subsequent tabs to open in
  // that window.
  bool opened_first_url = false;
  WindowOpenDisposition disposition = initial_disposition;
  OpenURLIterator iterator(nodes);
  while (iterator.has_next()) {
    const GURL* url = iterator.NextURL();
    // When |initial_disposition| is OFF_THE_RECORD, a node which can't be
    // opened in incognito window, it is detected using |browser_context|, is
    // not opened.
    if (initial_disposition == OFF_THE_RECORD &&
        !IsURLAllowedInIncognito(*url, browser_context))
      continue;

    content::WebContents* opened_tab = navigator->OpenURL(
        content::OpenURLParams(*url, content::Referrer(), disposition,
                               content::PAGE_TRANSITION_AUTO_BOOKMARK, false));

    if (!opened_first_url) {
      opened_first_url = true;
      disposition = NEW_BACKGROUND_TAB;
      // We opened the first URL which may have opened a new window or clobbered
      // the current page, reset the navigator just to be sure. |opened_tab| may
      // be NULL in tests.
      if (opened_tab)
        navigator = opened_tab;
    }
  }
}

void OpenAll(gfx::NativeWindow parent,
             content::PageNavigator* navigator,
             const BookmarkNode* node,
             WindowOpenDisposition initial_disposition,
             content::BrowserContext* browser_context) {
  std::vector<const BookmarkNode*> nodes;
  nodes.push_back(node);
  OpenAll(parent, navigator, nodes, initial_disposition, browser_context);
}

bool ConfirmDeleteBookmarkNode(const BookmarkNode* node,
                               gfx::NativeWindow window) {
  DCHECK(node && node->is_folder() && !node->empty());
  return ShowMessageBox(window,
      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
      l10n_util::GetStringFUTF16Int(IDS_BOOKMARK_EDITOR_CONFIRM_DELETE,
                                    ChildURLCountTotal(node)),
      MESSAGE_BOX_TYPE_QUESTION) == MESSAGE_BOX_RESULT_YES;
}

void ShowBookmarkAllTabsDialog(Browser* browser) {
  Profile* profile = browser->profile();
  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile);
  DCHECK(model && model->IsLoaded());

  const BookmarkNode* parent = model->GetParentForNewNodes();
  BookmarkEditor::EditDetails details =
      BookmarkEditor::EditDetails::AddFolder(parent, parent->child_count());
  GetURLsForOpenTabs(browser, &(details.urls));
  DCHECK(!details.urls.empty());

  BookmarkEditor::Show(browser->window()->GetNativeWindow(), profile, details,
                       BookmarkEditor::SHOW_TREE);
}

bool HasBookmarkURLs(const std::vector<const BookmarkNode*>& selection) {
  OpenURLIterator iterator(selection);
  return iterator.has_next();
}

bool HasBookmarkURLsAllowedInIncognitoMode(
    const std::vector<const BookmarkNode*>& selection,
    content::BrowserContext* browser_context) {
  OpenURLIterator iterator(selection);
  while (iterator.has_next()) {
    const GURL* url = iterator.NextURL();
    if (IsURLAllowedInIncognito(*url, browser_context))
      return true;
  }
  return false;
}

void GetURLAndTitleToBookmark(content::WebContents* web_contents,
                              GURL* url,
                              string16* title) {
  *url = web_contents->GetURL();
  *title = web_contents->GetTitle();
}

void ToggleBookmarkBarWhenVisible(content::BrowserContext* browser_context) {
  PrefService* prefs = components::UserPrefs::Get(browser_context);
  const bool always_show = !prefs->GetBoolean(prefs::kShowBookmarkBar);

  // The user changed when the bookmark bar is shown, update the preferences.
  prefs->SetBoolean(prefs::kShowBookmarkBar, always_show);
}

string16 FormatBookmarkURLForDisplay(const GURL& url,
                                     const PrefService* prefs) {
  std::string languages;
  if (prefs)
    languages = prefs->GetString(prefs::kAcceptLanguages);

  // Because this gets re-parsed by FixupURL(), it's safe to omit the scheme
  // and trailing slash, and unescape most characters.  However, it's
  // important not to drop any username/password, or unescape anything that
  // changes the URL's meaning.
  return net::FormatUrl(
      url, languages,
      net::kFormatUrlOmitAll & ~net::kFormatUrlOmitUsernamePassword,
      net::UnescapeRule::SPACES, NULL, NULL, NULL);
}

bool IsAppsShortcutEnabled(const Profile* profile) {
#if defined(USE_ASH)
  // Don't show the apps shortcut in ash when the app launcher is enabled.
  if (apps::WasAppLauncherEnabled())
    return false;
#endif

  return chrome::IsInstantExtendedAPIEnabled() && !profile->IsOffTheRecord();
}

bool ShouldShowAppsShortcutInBookmarkBar(Profile* profile) {
  return IsAppsShortcutEnabled(profile) &&
      profile->GetPrefs()->GetBoolean(prefs::kShowAppsShortcutInBookmarkBar);
}

}  // namespace chrome
<|endoftext|>