<commit_before>//===--- HeaderMap.cpp - A file that acts like dir of symlinks ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the HeaderMap interface.
//
//===----------------------------------------------------------------------===//

#include "clang/Lex/HeaderMap.h"
#include "clang/Lex/HeaderMapTypes.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/FileManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SwapByteOrder.h"
#include <cstdio>
#include <memory>
using namespace clang;

/// HashHMapKey - This is the 'well known' hash function required by the file
/// format, used to look up keys in the hash table.  The hash table uses simple
/// linear probing based on this function.
static inline unsigned HashHMapKey(StringRef Str) {
  unsigned Result = 0;
  const char *S = Str.begin(), *End = Str.end();

  for (; S != End; S++)
    Result += toLowercase(*S) * 13;
  return Result;
}

//===----------------------------------------------------------------------===//
// Verification and Construction
//===----------------------------------------------------------------------===//

/// HeaderMap::Create - This attempts to load the specified file as a header
/// map.  If it doesn't look like a HeaderMap, it gives up and returns null.
/// If it looks like a HeaderMap but is obviously corrupted, it puts a reason
/// into the string error argument and returns null.
const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) {
  // If the file is too small to be a header map, ignore it.
  unsigned FileSize = FE->getSize();
  if (FileSize <= sizeof(HMapHeader)) return nullptr;

  auto FileBuffer = FM.getBufferForFile(FE);
  if (!FileBuffer || !*FileBuffer)
    return nullptr;
  bool NeedsByteSwap;
  if (!checkHeader(**FileBuffer, NeedsByteSwap))
    return nullptr;
  return new HeaderMap(std::move(*FileBuffer), NeedsByteSwap);
}

bool HeaderMapImpl::checkHeader(const llvm::MemoryBuffer &File,
                                bool &NeedsByteSwap) {
  if (File.getBufferSize() <= sizeof(HMapHeader))
    return false;
  const char *FileStart = File.getBufferStart();

  // We know the file is at least as big as the header, check it now.
  const HMapHeader *Header = reinterpret_cast<const HMapHeader*>(FileStart);

  // Sniff it to see if it's a headermap by checking the magic number and
  // version.
  if (Header->Magic == HMAP_HeaderMagicNumber &&
      Header->Version == HMAP_HeaderVersion)
    NeedsByteSwap = false;
  else if (Header->Magic == llvm::ByteSwap_32(HMAP_HeaderMagicNumber) &&
           Header->Version == llvm::ByteSwap_16(HMAP_HeaderVersion))
    NeedsByteSwap = true;  // Mixed endianness headermap.
  else
    return false;  // Not a header map.

  if (Header->Reserved != 0)
    return false;

  // Check the number of buckets.  It should be a power of two, and there
  // should be enough space in the file for all of them.
  auto NumBuckets = NeedsByteSwap
                        ? llvm::sys::getSwappedBytes(Header->NumBuckets)
                        : Header->NumBuckets;
  if (NumBuckets & (NumBuckets - 1))
    return false;
  if (File.getBufferSize() <
      sizeof(HMapHeader) + sizeof(HMapBucket) * NumBuckets)
    return false;

  // Okay, everything looks good.
  return true;
}

//===----------------------------------------------------------------------===//
//  Utility Methods
//===----------------------------------------------------------------------===//

/// getFileName - Return the filename of the headermap.
const char *HeaderMapImpl::getFileName() const {
  return FileBuffer->getBufferIdentifier();
}

unsigned HeaderMapImpl::getEndianAdjustedWord(unsigned X) const {
  if (!NeedsBSwap) return X;
  return llvm::ByteSwap_32(X);
}

/// getHeader - Return a reference to the file header, in unbyte-swapped form.
/// This method cannot fail.
const HMapHeader &HeaderMapImpl::getHeader() const {
  // We know the file is at least as big as the header.  Return it.
  return *reinterpret_cast<const HMapHeader*>(FileBuffer->getBufferStart());
}

/// getBucket - Return the specified hash table bucket from the header map,
/// bswap'ing its fields as appropriate.  If the bucket number is not valid,
/// this return a bucket with an empty key (0).
HMapBucket HeaderMapImpl::getBucket(unsigned BucketNo) const {
  assert(FileBuffer->getBufferSize() >=
             sizeof(HMapHeader) + sizeof(HMapBucket) * BucketNo &&
         "Expected bucket to be in range");

  HMapBucket Result;
  Result.Key = HMAP_EmptyBucketKey;

  const HMapBucket *BucketArray =
    reinterpret_cast<const HMapBucket*>(FileBuffer->getBufferStart() +
                                        sizeof(HMapHeader));
  const HMapBucket *BucketPtr = BucketArray+BucketNo;

  // Load the values, bswapping as needed.
  Result.Key    = getEndianAdjustedWord(BucketPtr->Key);
  Result.Prefix = getEndianAdjustedWord(BucketPtr->Prefix);
  Result.Suffix = getEndianAdjustedWord(BucketPtr->Suffix);
  return Result;
}

/// getString - Look up the specified string in the string table.  If the string
/// index is not valid, it returns an empty string.
const char *HeaderMapImpl::getString(unsigned StrTabIdx) const {
  // Add the start of the string table to the idx.
  StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset);

  // Check for invalid index.
  if (StrTabIdx >= FileBuffer->getBufferSize())
    return nullptr;

  // Otherwise, we have a valid pointer into the file.  Just return it.  We know
  // that the "string" can not overrun the end of the file, because the buffer
  // is nul terminated by virtue of being a MemoryBuffer.
  return FileBuffer->getBufferStart()+StrTabIdx;
}

//===----------------------------------------------------------------------===//
// The Main Drivers
//===----------------------------------------------------------------------===//

/// dump - Print the contents of this headermap to stderr.
LLVM_DUMP_METHOD void HeaderMapImpl::dump() const {
  const HMapHeader &Hdr = getHeader();
  unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);

  fprintf(stderr, "Header Map %s:\n  %d buckets, %d entries\n",
          getFileName(), NumBuckets,
          getEndianAdjustedWord(Hdr.NumEntries));

  for (unsigned i = 0; i != NumBuckets; ++i) {
    HMapBucket B = getBucket(i);
    if (B.Key == HMAP_EmptyBucketKey) continue;

    const char *Key    = getString(B.Key);
    const char *Prefix = getString(B.Prefix);
    const char *Suffix = getString(B.Suffix);
    fprintf(stderr, "  %d. %s -> '%s' '%s'\n", i, Key, Prefix, Suffix);
  }
}

/// LookupFile - Check to see if the specified relative filename is located in
/// this HeaderMap.  If so, open it and return its FileEntry.
const FileEntry *HeaderMap::LookupFile(
    StringRef Filename, FileManager &FM) const {

  SmallString<1024> Path;
  StringRef Dest = HeaderMapImpl::lookupFilename(Filename, Path);
  if (Dest.empty())
    return nullptr;

  return FM.getFile(Dest);
}

StringRef HeaderMapImpl::lookupFilename(StringRef Filename,
                                        SmallVectorImpl<char> &DestPath) const {
  const HMapHeader &Hdr = getHeader();
  unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);

  // Don't probe infinitely.  This should be checked before constructing.
  assert(!(NumBuckets & (NumBuckets - 1)) && "Expected power of 2");

  // Linearly probe the hash table.
  for (unsigned Bucket = HashHMapKey(Filename);; ++Bucket) {
    HMapBucket B = getBucket(Bucket & (NumBuckets-1));
    if (B.Key == HMAP_EmptyBucketKey) return StringRef(); // Hash miss.

    // See if the key matches.  If not, probe on.
    if (!Filename.equals_lower(getString(B.Key)))
      continue;

    // If so, we have a match in the hash table.  Construct the destination
    // path.
    StringRef Prefix = getString(B.Prefix);
    StringRef Suffix = getString(B.Suffix);
    DestPath.clear();
    DestPath.append(Prefix.begin(), Prefix.end());
    DestPath.append(Suffix.begin(), Suffix.end());
    return StringRef(DestPath.begin(), DestPath.size());
  }
}
<commit_msg>Lex: Use dbgs() instead of fprintf() in HeaderMap::dump()<commit_after>//===--- HeaderMap.cpp - A file that acts like dir of symlinks ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the HeaderMap interface.
//
//===----------------------------------------------------------------------===//

#include "clang/Lex/HeaderMap.h"
#include "clang/Lex/HeaderMapTypes.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/FileManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SwapByteOrder.h"
#include "llvm/Support/Debug.h"
#include <memory>
using namespace clang;

/// HashHMapKey - This is the 'well known' hash function required by the file
/// format, used to look up keys in the hash table.  The hash table uses simple
/// linear probing based on this function.
static inline unsigned HashHMapKey(StringRef Str) {
  unsigned Result = 0;
  const char *S = Str.begin(), *End = Str.end();

  for (; S != End; S++)
    Result += toLowercase(*S) * 13;
  return Result;
}

//===----------------------------------------------------------------------===//
// Verification and Construction
//===----------------------------------------------------------------------===//

/// HeaderMap::Create - This attempts to load the specified file as a header
/// map.  If it doesn't look like a HeaderMap, it gives up and returns null.
/// If it looks like a HeaderMap but is obviously corrupted, it puts a reason
/// into the string error argument and returns null.
const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) {
  // If the file is too small to be a header map, ignore it.
  unsigned FileSize = FE->getSize();
  if (FileSize <= sizeof(HMapHeader)) return nullptr;

  auto FileBuffer = FM.getBufferForFile(FE);
  if (!FileBuffer || !*FileBuffer)
    return nullptr;
  bool NeedsByteSwap;
  if (!checkHeader(**FileBuffer, NeedsByteSwap))
    return nullptr;
  return new HeaderMap(std::move(*FileBuffer), NeedsByteSwap);
}

bool HeaderMapImpl::checkHeader(const llvm::MemoryBuffer &File,
                                bool &NeedsByteSwap) {
  if (File.getBufferSize() <= sizeof(HMapHeader))
    return false;
  const char *FileStart = File.getBufferStart();

  // We know the file is at least as big as the header, check it now.
  const HMapHeader *Header = reinterpret_cast<const HMapHeader*>(FileStart);

  // Sniff it to see if it's a headermap by checking the magic number and
  // version.
  if (Header->Magic == HMAP_HeaderMagicNumber &&
      Header->Version == HMAP_HeaderVersion)
    NeedsByteSwap = false;
  else if (Header->Magic == llvm::ByteSwap_32(HMAP_HeaderMagicNumber) &&
           Header->Version == llvm::ByteSwap_16(HMAP_HeaderVersion))
    NeedsByteSwap = true;  // Mixed endianness headermap.
  else
    return false;  // Not a header map.

  if (Header->Reserved != 0)
    return false;

  // Check the number of buckets.  It should be a power of two, and there
  // should be enough space in the file for all of them.
  auto NumBuckets = NeedsByteSwap
                        ? llvm::sys::getSwappedBytes(Header->NumBuckets)
                        : Header->NumBuckets;
  if (NumBuckets & (NumBuckets - 1))
    return false;
  if (File.getBufferSize() <
      sizeof(HMapHeader) + sizeof(HMapBucket) * NumBuckets)
    return false;

  // Okay, everything looks good.
  return true;
}

//===----------------------------------------------------------------------===//
//  Utility Methods
//===----------------------------------------------------------------------===//

/// getFileName - Return the filename of the headermap.
const char *HeaderMapImpl::getFileName() const {
  return FileBuffer->getBufferIdentifier();
}

unsigned HeaderMapImpl::getEndianAdjustedWord(unsigned X) const {
  if (!NeedsBSwap) return X;
  return llvm::ByteSwap_32(X);
}

/// getHeader - Return a reference to the file header, in unbyte-swapped form.
/// This method cannot fail.
const HMapHeader &HeaderMapImpl::getHeader() const {
  // We know the file is at least as big as the header.  Return it.
  return *reinterpret_cast<const HMapHeader*>(FileBuffer->getBufferStart());
}

/// getBucket - Return the specified hash table bucket from the header map,
/// bswap'ing its fields as appropriate.  If the bucket number is not valid,
/// this return a bucket with an empty key (0).
HMapBucket HeaderMapImpl::getBucket(unsigned BucketNo) const {
  assert(FileBuffer->getBufferSize() >=
             sizeof(HMapHeader) + sizeof(HMapBucket) * BucketNo &&
         "Expected bucket to be in range");

  HMapBucket Result;
  Result.Key = HMAP_EmptyBucketKey;

  const HMapBucket *BucketArray =
    reinterpret_cast<const HMapBucket*>(FileBuffer->getBufferStart() +
                                        sizeof(HMapHeader));
  const HMapBucket *BucketPtr = BucketArray+BucketNo;

  // Load the values, bswapping as needed.
  Result.Key    = getEndianAdjustedWord(BucketPtr->Key);
  Result.Prefix = getEndianAdjustedWord(BucketPtr->Prefix);
  Result.Suffix = getEndianAdjustedWord(BucketPtr->Suffix);
  return Result;
}

/// getString - Look up the specified string in the string table.  If the string
/// index is not valid, it returns an empty string.
const char *HeaderMapImpl::getString(unsigned StrTabIdx) const {
  // Add the start of the string table to the idx.
  StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset);

  // Check for invalid index.
  if (StrTabIdx >= FileBuffer->getBufferSize())
    return nullptr;

  // Otherwise, we have a valid pointer into the file.  Just return it.  We know
  // that the "string" can not overrun the end of the file, because the buffer
  // is nul terminated by virtue of being a MemoryBuffer.
  return FileBuffer->getBufferStart()+StrTabIdx;
}

//===----------------------------------------------------------------------===//
// The Main Drivers
//===----------------------------------------------------------------------===//

/// dump - Print the contents of this headermap to stderr.
LLVM_DUMP_METHOD void HeaderMapImpl::dump() const {
  const HMapHeader &Hdr = getHeader();
  unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);

  llvm::dbgs() << "Header Map " << getFileName() << ":\n  " << NumBuckets
               << ", " << getEndianAdjustedWord(Hdr.NumEntries) << "\n";

  for (unsigned i = 0; i != NumBuckets; ++i) {
    HMapBucket B = getBucket(i);
    if (B.Key == HMAP_EmptyBucketKey) continue;

    const char *Key    = getString(B.Key);
    const char *Prefix = getString(B.Prefix);
    const char *Suffix = getString(B.Suffix);
    llvm::dbgs() << "  " << i << ". " << Key << " -> '" << Prefix << "' '"
                 << Suffix << "'\n";
  }
}

/// LookupFile - Check to see if the specified relative filename is located in
/// this HeaderMap.  If so, open it and return its FileEntry.
const FileEntry *HeaderMap::LookupFile(
    StringRef Filename, FileManager &FM) const {

  SmallString<1024> Path;
  StringRef Dest = HeaderMapImpl::lookupFilename(Filename, Path);
  if (Dest.empty())
    return nullptr;

  return FM.getFile(Dest);
}

StringRef HeaderMapImpl::lookupFilename(StringRef Filename,
                                        SmallVectorImpl<char> &DestPath) const {
  const HMapHeader &Hdr = getHeader();
  unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);

  // Don't probe infinitely.  This should be checked before constructing.
  assert(!(NumBuckets & (NumBuckets - 1)) && "Expected power of 2");

  // Linearly probe the hash table.
  for (unsigned Bucket = HashHMapKey(Filename);; ++Bucket) {
    HMapBucket B = getBucket(Bucket & (NumBuckets-1));
    if (B.Key == HMAP_EmptyBucketKey) return StringRef(); // Hash miss.

    // See if the key matches.  If not, probe on.
    if (!Filename.equals_lower(getString(B.Key)))
      continue;

    // If so, we have a match in the hash table.  Construct the destination
    // path.
    StringRef Prefix = getString(B.Prefix);
    StringRef Suffix = getString(B.Suffix);
    DestPath.clear();
    DestPath.append(Prefix.begin(), Prefix.end());
    DestPath.append(Suffix.begin(), Suffix.end());
    return StringRef(DestPath.begin(), DestPath.size());
  }
}
<|endoftext|>


<commit_before>#include <cstdio>               // printf(), fprintf()
#include "speech_recognizer.h"
#include "core/os/memory.h"     // memalloc(), memfree(), memdelete()

/*
 * Adds the -adcdev option as a possible command line argument.
 * This argument corresponds to the microphone name.
 */
static arg_t cont_args_def[] = {
    POCKETSPHINX_OPTIONS,
    // Microphone
    {"-adcdev",
     ARG_STRING,
     NULL,  // Use default system microphone
     "Name of audio device to use for input."},
    CMDLN_EMPTY_OPTION
};

SpeechRecognizer::Error SpeechRecognizer::config(String hmm_dirname,
                              String dict_filename,
                              String kws_filename) {
    this->hmm_dirname = hmm_dirname;
    this->dict_filename = dict_filename;
    this->kws_filename = kws_filename;

    String names[3];
    names[0] = hmm_dirname;
    names[1] = dict_filename;
    names[2] = kws_filename;

    char *convert[3];
    hmm = convert[0];
    dict = convert[1];
    kws = convert[2];

    // Convert each filename: String -> wchar_t * -> char *
    for (int i = 0; i < 3; i++) {
        int len = wcstombs(NULL, names[i].c_str(), 0);
        if (len == -1)
            return MULTIBYTE_STR_ERR;

        convert[i] = (char *) memalloc((len + 1) * sizeof(char));
        if (convert[i] == NULL)
            return MEMALLOC_ERR;

        wcstombs(convert[i], names[i].c_str(), len + 1);

        #ifdef DEBUG_ENABLED
            printf("[SpeechRecognizer Argument] %s\n", convert[i]);
        #endif
    }

    // Create configuration variable
    conf = cmd_ln_init(NULL, ps_args(), TRUE,
                        "-hmm", convert[0],
                        "-dict", convert[1],
                        "-kws", convert[2],
                        NULL);

    if (conf == NULL)
        return CONFIG_CREATE_ERR;

    // Update basic configuration with custom one for mic
    conf = cmd_ln_init(conf, cont_args_def, TRUE, NULL);
    if (conf == NULL)
        return CONFIG_CREATE_ERR;

    // Create recorder variable
    recorder = ad_open_dev(cmd_ln_str_r(conf, "-adcdev"),
                            (int) cmd_ln_float32_r(conf, "-samprate"));

    if (recorder == NULL) {
        cmd_ln_free_r(conf);
        return AUDIO_DEV_OPEN_ERR;
    }

    // Creater decoder variable
    decoder = ps_init(conf);

    if (decoder == NULL) {
        cmd_ln_free_r(conf);
        ad_close(recorder);
        return DECODER_CREATE_ERR;
    }

    return OK;
}

SpeechRecognizer::Error SpeechRecognizer::run() {
    if (conf == NULL || recorder == NULL || decoder == NULL)
        return NO_CONFIG_ERR;

    is_running = true;
    running_err = OK;
    recognition = Thread::create(SpeechRecognizer::thread_recognize, this);

    return OK;
}

bool SpeechRecognizer::running() {
    return is_running;
}

void SpeechRecognizer::stop() {
    if (recognition != NULL) {
        is_running = false;
        Thread::wait_to_finish(recognition);
        memdelete(recognition);
        recognition = NULL;
    }
}

void SpeechRecognizer::thread_recognize(void *sr) {
    SpeechRecognizer *self = (SpeechRecognizer *) sr;
    self->recognize();
}

void SpeechRecognizer::recognize() {
    int current_buffer_size = rec_buffer_size;
    int16 buffer[current_buffer_size];
    int32 n;
    const char *hyp;

    // Start recording
    if (ad_start_rec(recorder) < 0) {
        is_running = false;
        running_err = REC_START_ERR;
    }

    // Start utterance
    if (ps_start_utt(decoder) < 0) {
        is_running = false;
        running_err = UTT_START_ERR;
    }

    while (is_running) {
        // Read data from microphone
        if ((n = ad_read(recorder, buffer, current_buffer_size)) < 0) {
            is_running = false;
            running_err = AUDIO_READ_ERR;
        }

        // Process captured sound
        ps_process_raw(decoder, buffer, n, FALSE, FALSE);

        // Check for keyword in captured sound
        hyp = ps_get_hyp(decoder, NULL);
        if (hyp != NULL) {
            if (buffer_size() + 1 <= kws_buffer_cap) {
                kws_buffer.push_back(String(hyp));

                #ifdef DEBUG_ENABLED
                    printf("[SpeechRecognizer] %s\n", hyp);
                #endif
            }
            else {
                fprintf(stderr,
                        "Warning: SpeechRecognizer buffer is full! Cannot store "
                        "more keywords!\n");
            }

            // Restart decoder
            ps_end_utt(decoder);
            if (ps_start_utt(decoder) < 0) {
                is_running = false;
                running_err = UTT_RESTART_ERR;
            }
        }
    }

    // Stop recording
    if (ad_stop_rec(recorder) < 0)
        running_err = REC_STOP_ERR;
}

SpeechRecognizer::Error SpeechRecognizer::get_run_error() {
    return running_err;
}

void SpeechRecognizer::reset_run_error() {
    running_err = OK;
}

String SpeechRecognizer::buffer_get() {
    if (buffer_empty())
        return String("");

    String keyword = kws_buffer.get(0);
    kws_buffer.remove(0);
    return keyword;
}

int SpeechRecognizer::buffer_size() {
    return kws_buffer.size();
}

bool SpeechRecognizer::buffer_empty() {
    return kws_buffer.empty();
}

void SpeechRecognizer::buffer_clear() {
    kws_buffer.clear();
}

int SpeechRecognizer::get_rec_buffer_size() {
    return rec_buffer_size;
}

void SpeechRecognizer::set_rec_buffer_size(int rec_buffer_size) {
    if (rec_buffer_size <= 0) {
        fprintf(stderr, "Microphone recorder buffer size must be greater than 0\n");
        return;
    }
    this->rec_buffer_size = rec_buffer_size;
}

int SpeechRecognizer::get_kws_buffer_cap() {
    return kws_buffer_cap;
}

void SpeechRecognizer::set_kws_buffer_cap(int kws_buffer_cap) {
    if (kws_buffer_cap <= 0) {
        fprintf(stderr, "Keywords buffer capacity must be greater than 0\n");
        return;
    }
    this->kws_buffer_cap = kws_buffer_cap;
}

void SpeechRecognizer::_bind_methods() {
    ObjectTypeDB::bind_method("config", &SpeechRecognizer::config);
    ObjectTypeDB::bind_method("run", &SpeechRecognizer::run);
    ObjectTypeDB::bind_method("running", &SpeechRecognizer::running);
    ObjectTypeDB::bind_method("stop", &SpeechRecognizer::stop);

    ObjectTypeDB::bind_method("get_run_error", &SpeechRecognizer::get_run_error);
    ObjectTypeDB::bind_method("reset_run_error", &SpeechRecognizer::reset_run_error);

    ObjectTypeDB::bind_method("buffer_get", &SpeechRecognizer::buffer_get);
    ObjectTypeDB::bind_method("buffer_size", &SpeechRecognizer::buffer_size);
    ObjectTypeDB::bind_method("buffer_empty", &SpeechRecognizer::buffer_empty);
    ObjectTypeDB::bind_method("buffer_clear", &SpeechRecognizer::buffer_clear);

    ObjectTypeDB::bind_method("get_rec_buffer_size",
                              &SpeechRecognizer::get_rec_buffer_size);
    ObjectTypeDB::bind_method("set_rec_buffer_size",
                              &SpeechRecognizer::set_rec_buffer_size);
    ObjectTypeDB::bind_method("get_kws_buffer_cap",
                              &SpeechRecognizer::get_kws_buffer_cap);
    ObjectTypeDB::bind_method("set_kws_buffer_cap",
                              &SpeechRecognizer::set_kws_buffer_cap);
}

SpeechRecognizer::SpeechRecognizer() {
    // Disable Pocketphinx log output
    err_set_logfp(NULL);

    conf = NULL; recorder = NULL; decoder = NULL;

    hmm_dirname   = "";
    dict_filename = "";
    kws_filename  = "";

    hmm = NULL; dict = NULL; kws = NULL;

    recognition = NULL;
    is_running = false;
    running_err = OK;

    rec_buffer_size = DEFAULT_REC_BUFFER_SIZE;
    kws_buffer_cap = DEFAULT_KWS_BUFFER_CAP;
}

SpeechRecognizer::~SpeechRecognizer() {
    if (recognition != NULL) {
        is_running = false;
        Thread::wait_to_finish(recognition);
        memdelete(recognition);
    }

    if (recorder != NULL) ad_close(recorder);
    if (decoder  != NULL) ps_free(decoder);
    if (conf     != NULL) cmd_ln_free_r(conf);

    if (hmm != NULL)  memfree(hmm);
    if (dict != NULL) memfree(dict);
    if (kws != NULL)  memfree(kws);
}
<commit_msg>Print message to stderr when getting word from empty buffer<commit_after>#include <cstdio>               // printf(), fprintf()
#include "speech_recognizer.h"
#include "core/os/memory.h"     // memalloc(), memfree(), memdelete()

/*
 * Adds the -adcdev option as a possible command line argument.
 * This argument corresponds to the microphone name.
 */
static arg_t cont_args_def[] = {
    POCKETSPHINX_OPTIONS,
    // Microphone
    {"-adcdev",
     ARG_STRING,
     NULL,  // Use default system microphone
     "Name of audio device to use for input."},
    CMDLN_EMPTY_OPTION
};

SpeechRecognizer::Error SpeechRecognizer::config(String hmm_dirname,
                              String dict_filename,
                              String kws_filename) {
    this->hmm_dirname = hmm_dirname;
    this->dict_filename = dict_filename;
    this->kws_filename = kws_filename;

    String names[3];
    names[0] = hmm_dirname;
    names[1] = dict_filename;
    names[2] = kws_filename;

    char *convert[3];
    hmm = convert[0];
    dict = convert[1];
    kws = convert[2];

    // Convert each filename: String -> wchar_t * -> char *
    for (int i = 0; i < 3; i++) {
        int len = wcstombs(NULL, names[i].c_str(), 0);
        if (len == -1)
            return MULTIBYTE_STR_ERR;

        convert[i] = (char *) memalloc((len + 1) * sizeof(char));
        if (convert[i] == NULL)
            return MEMALLOC_ERR;

        wcstombs(convert[i], names[i].c_str(), len + 1);

        #ifdef DEBUG_ENABLED
            printf("[SpeechRecognizer Argument] %s\n", convert[i]);
        #endif
    }

    // Create configuration variable
    conf = cmd_ln_init(NULL, ps_args(), TRUE,
                        "-hmm", convert[0],
                        "-dict", convert[1],
                        "-kws", convert[2],
                        NULL);

    if (conf == NULL)
        return CONFIG_CREATE_ERR;

    // Update basic configuration with custom one for mic
    conf = cmd_ln_init(conf, cont_args_def, TRUE, NULL);
    if (conf == NULL)
        return CONFIG_CREATE_ERR;

    // Create recorder variable
    recorder = ad_open_dev(cmd_ln_str_r(conf, "-adcdev"),
                            (int) cmd_ln_float32_r(conf, "-samprate"));

    if (recorder == NULL) {
        cmd_ln_free_r(conf);
        return AUDIO_DEV_OPEN_ERR;
    }

    // Creater decoder variable
    decoder = ps_init(conf);

    if (decoder == NULL) {
        cmd_ln_free_r(conf);
        ad_close(recorder);
        return DECODER_CREATE_ERR;
    }

    return OK;
}

SpeechRecognizer::Error SpeechRecognizer::run() {
    if (conf == NULL || recorder == NULL || decoder == NULL)
        return NO_CONFIG_ERR;

    is_running = true;
    running_err = OK;
    recognition = Thread::create(SpeechRecognizer::thread_recognize, this);

    return OK;
}

bool SpeechRecognizer::running() {
    return is_running;
}

void SpeechRecognizer::stop() {
    if (recognition != NULL) {
        is_running = false;
        Thread::wait_to_finish(recognition);
        memdelete(recognition);
        recognition = NULL;
    }
}

void SpeechRecognizer::thread_recognize(void *sr) {
    SpeechRecognizer *self = (SpeechRecognizer *) sr;
    self->recognize();
}

void SpeechRecognizer::recognize() {
    int current_buffer_size = rec_buffer_size;
    int16 buffer[current_buffer_size];
    int32 n;
    const char *hyp;

    // Start recording
    if (ad_start_rec(recorder) < 0) {
        is_running = false;
        running_err = REC_START_ERR;
    }

    // Start utterance
    if (ps_start_utt(decoder) < 0) {
        is_running = false;
        running_err = UTT_START_ERR;
    }

    while (is_running) {
        // Read data from microphone
        if ((n = ad_read(recorder, buffer, current_buffer_size)) < 0) {
            is_running = false;
            running_err = AUDIO_READ_ERR;
        }

        // Process captured sound
        ps_process_raw(decoder, buffer, n, FALSE, FALSE);

        // Check for keyword in captured sound
        hyp = ps_get_hyp(decoder, NULL);
        if (hyp != NULL) {
            if (buffer_size() + 1 <= kws_buffer_cap) {
                kws_buffer.push_back(String(hyp));

                #ifdef DEBUG_ENABLED
                    printf("[SpeechRecognizer] %s\n", hyp);
                #endif
            }
            else {
                fprintf(stderr,
                        "Warning: SpeechRecognizer buffer is full! Cannot store "
                        "more keywords!\n");
            }

            // Restart decoder
            ps_end_utt(decoder);
            if (ps_start_utt(decoder) < 0) {
                is_running = false;
                running_err = UTT_RESTART_ERR;
            }
        }
    }

    // Stop recording
    if (ad_stop_rec(recorder) < 0)
        running_err = REC_STOP_ERR;
}

SpeechRecognizer::Error SpeechRecognizer::get_run_error() {
    return running_err;
}

void SpeechRecognizer::reset_run_error() {
    running_err = OK;
}

String SpeechRecognizer::buffer_get() {
    if (buffer_empty()) {
        fprintf(stderr, "Warning: Empty keywords buffer, returning empty String!\n");
        return String("");
    }

    String keyword = kws_buffer.get(0);
    kws_buffer.remove(0);
    return keyword;
}

int SpeechRecognizer::buffer_size() {
    return kws_buffer.size();
}

bool SpeechRecognizer::buffer_empty() {
    return kws_buffer.empty();
}

void SpeechRecognizer::buffer_clear() {
    kws_buffer.clear();
}

int SpeechRecognizer::get_rec_buffer_size() {
    return rec_buffer_size;
}

void SpeechRecognizer::set_rec_buffer_size(int rec_buffer_size) {
    if (rec_buffer_size <= 0) {
        fprintf(stderr, "Microphone recorder buffer size must be greater than 0\n");
        return;
    }
    this->rec_buffer_size = rec_buffer_size;
}

int SpeechRecognizer::get_kws_buffer_cap() {
    return kws_buffer_cap;
}

void SpeechRecognizer::set_kws_buffer_cap(int kws_buffer_cap) {
    if (kws_buffer_cap <= 0) {
        fprintf(stderr, "Keywords buffer capacity must be greater than 0\n");
        return;
    }
    this->kws_buffer_cap = kws_buffer_cap;
}

void SpeechRecognizer::_bind_methods() {
    ObjectTypeDB::bind_method("config", &SpeechRecognizer::config);
    ObjectTypeDB::bind_method("run", &SpeechRecognizer::run);
    ObjectTypeDB::bind_method("running", &SpeechRecognizer::running);
    ObjectTypeDB::bind_method("stop", &SpeechRecognizer::stop);

    ObjectTypeDB::bind_method("get_run_error", &SpeechRecognizer::get_run_error);
    ObjectTypeDB::bind_method("reset_run_error", &SpeechRecognizer::reset_run_error);

    ObjectTypeDB::bind_method("buffer_get", &SpeechRecognizer::buffer_get);
    ObjectTypeDB::bind_method("buffer_size", &SpeechRecognizer::buffer_size);
    ObjectTypeDB::bind_method("buffer_empty", &SpeechRecognizer::buffer_empty);
    ObjectTypeDB::bind_method("buffer_clear", &SpeechRecognizer::buffer_clear);

    ObjectTypeDB::bind_method("get_rec_buffer_size",
                              &SpeechRecognizer::get_rec_buffer_size);
    ObjectTypeDB::bind_method("set_rec_buffer_size",
                              &SpeechRecognizer::set_rec_buffer_size);
    ObjectTypeDB::bind_method("get_kws_buffer_cap",
                              &SpeechRecognizer::get_kws_buffer_cap);
    ObjectTypeDB::bind_method("set_kws_buffer_cap",
                              &SpeechRecognizer::set_kws_buffer_cap);
}

SpeechRecognizer::SpeechRecognizer() {
    // Disable Pocketphinx log output
    err_set_logfp(NULL);

    conf = NULL; recorder = NULL; decoder = NULL;

    hmm_dirname   = "";
    dict_filename = "";
    kws_filename  = "";

    hmm = NULL; dict = NULL; kws = NULL;

    recognition = NULL;
    is_running = false;
    running_err = OK;

    rec_buffer_size = DEFAULT_REC_BUFFER_SIZE;
    kws_buffer_cap = DEFAULT_KWS_BUFFER_CAP;
}

SpeechRecognizer::~SpeechRecognizer() {
    if (recognition != NULL) {
        is_running = false;
        Thread::wait_to_finish(recognition);
        memdelete(recognition);
    }

    if (recorder != NULL) ad_close(recorder);
    if (decoder  != NULL) ps_free(decoder);
    if (conf     != NULL) cmd_ln_free_r(conf);

    if (hmm != NULL)  memfree(hmm);
    if (dict != NULL) memfree(dict);
    if (kws != NULL)  memfree(kws);
}
<|endoftext|>


<commit_before>//
//  NSolver::solve.cpp
//
//  Created by Lei Qiao on 15/8/9.
//  A work based on deal.II tutorial step-33.
//

#include <NSolver/solver/NSolver.h>

namespace NSFEMSolver
{
  using namespace dealii;

  // @sect4{NSolver::solve}
  //
  // Here, we actually solve the linear system, using either of Trilinos'
  // Aztec or Amesos linear solvers. The result of the computation will be
  // written into the argument vector passed to this function. The result is a
  // pair of number of iterations and the final linear residual.

  template <int dim>
  std::pair<unsigned int, double>
  NSolver<dim>::solve (NSVector &newton_update)
  {
    std::pair<unsigned int, double> return_value (-1, -1);
    switch (parameters->solver)
      {
      // If the parameter file specified that a direct solver shall be used,
      // then we'll get here. The process is straightforward, since deal.II
      // provides a wrapper class to the Amesos direct solver within
      // Trilinos. All we have to do is to create a solver control object
      // (which is just a dummy object here, since we won't perform any
      // iterations), and then create the direct solver object. When
      // actually doing the solve, note that we don't pass a
      // preconditioner. That wouldn't make much sense for a direct solver
      // anyway.  At the end we return the solver control statistics —
      // which will tell that no iterations have been performed and that the
      // final linear residual is zero, absent any better information that
      // may be provided here:
      case Parameters::Solver::direct:
      {
        SolverControl solver_control (1,0);

        TrilinosWrappers::SolverDirect::AdditionalData
        solver_data (parameters->output == Parameters::Solver::verbose);
        TrilinosWrappers::SolverDirect direct (solver_control, solver_data);

        direct.solve (system_matrix, newton_update, right_hand_side);

        return_value.first = solver_control.last_step();
        return_value.second = solver_control.last_value();
        break;
      }

      // Likewise, if we are to use an iterative solver, we use Aztec's GMRES
      // solver. We could use the Trilinos wrapper classes for iterative
      // solvers and preconditioners here as well, but we choose to use an
      // Aztec solver directly. For the given problem, Aztec's internal
      // preconditioner implementations are superior over the ones deal.II has
      // wrapper classes to, so we use ILU-T preconditioning within the
      // AztecOO solver and set a bunch of options that can be changed from
      // the parameter file.
      //
      // There are two more practicalities: Since we have built our right hand
      // side and solution vector as deal.II Vector objects (as opposed to the
      // matrix, which is a Trilinos object), we must hand the solvers
      // Trilinos Epetra vectors.  Luckily, they support the concept of a
      // 'view', so we just send in a pointer to our deal.II vectors. We have
      // to provide an Epetra_Map for the vector that sets the parallel
      // distribution, which is just a dummy object in serial. The easiest way
      // is to ask the matrix for its map, and we're going to be ready for
      // matrix-vector products with it.
      //
      // Secondly, the Aztec solver wants us to pass a Trilinos
      // Epetra_CrsMatrix in, not the deal.II wrapper class itself. So we
      // access to the actual Trilinos matrix in the Trilinos wrapper class by
      // the command trilinos_matrix(). Trilinos wants the matrix to be
      // non-constant, so we have to manually remove the constantness using a
      // const_cast.
      case Parameters::Solver::gmres:
      {
        Epetra_Vector x (View, system_matrix.trilinos_matrix().DomainMap(),
                         newton_update.begin());
        Epetra_Vector b (View, system_matrix.trilinos_matrix().RangeMap(),
                         right_hand_side.begin());

        AztecOO solver;
        solver.SetAztecOption (AZ_output,
                               (parameters->output ==
                                Parameters::Solver::quiet
                                ?
                                AZ_none
                                :
                                AZ_all));
        solver.SetAztecOption (AZ_solver, AZ_gmres);
        solver.SetAztecOption (AZ_kspace, parameters->AZ_Krylov_space);
        solver.SetRHS (&b);
        solver.SetLHS (&x);

        Epetra_Operator *preconditioner_ptr (0);
        switch (parameters->prec_type)
          {
          case Parameters::Solver::NoPrec:
          {
            solver.SetAztecOption (AZ_precond, AZ_none);
            break;
          }
          case Parameters::Solver::AZ_DD:
          {
            solver.SetAztecOption (AZ_precond,  AZ_dom_decomp);
            solver.SetAztecOption (AZ_subdomain_solve, AZ_ilut);
            solver.SetAztecOption (AZ_overlap,  0);
            solver.SetAztecOption (AZ_reorder,  parameters->AZ_RCM_reorder);

            solver.SetAztecParam (AZ_drop,      parameters->ilut_drop);
            solver.SetAztecParam (AZ_ilut_fill, parameters->ilut_fill);
            solver.SetAztecParam (AZ_athresh,   parameters->ilut_atol);
            solver.SetAztecParam (AZ_rthresh,   parameters->ilut_rtol);
            break;
          }
          case Parameters::Solver::AZ_AMG:
          {
            // for parameter_list.set ("null space: dimension", int)
            const int n_components = EquationComponents<dim>::n_components;
            // Build the AMG preconditioner.
            Teuchos::ParameterList parameter_list;
            // Equation is not elliptic
            ML_Epetra::SetDefaults ("NSSA", parameter_list);
            parameter_list.set ("aggregation: type", "Uncoupled");
            parameter_list.set ("aggregation: block scaling", true);

            parameter_list.set ("smoother: type", "Chebyshev");
            parameter_list.set ("coarse: type", "Amesos-KLU");

            parameter_list.set ("smoother: sweeps", 2);
            parameter_list.set ("cycle applications", 1);
            // W-cycle
            // parameter_list.set ("prec type", "MGW");
            // V-cycle
            parameter_list.set ("prec type", "MGV");

            parameter_list.set ("smoother: Chebyshev alpha",10.);
            parameter_list.set ("smoother: ifpack overlap", 0);
            parameter_list.set ("aggregation: threshold", 1.0e-4);
            parameter_list.set ("coarse: max size", 2000);
            // No detail output
            parameter_list.set ("ML output", 0);

            parameter_list.set ("null space: type", "pre-computed");
            parameter_list.set ("null space: dimension", n_components);

            // Setup constant modes
            const Epetra_CrsMatrix &matrix = system_matrix.trilinos_matrix();
            const Epetra_Map &domain_map = matrix.OperatorDomainMap();

            Epetra_MultiVector distributed_constant_modes (domain_map, n_components);
            std::vector<TrilinosScalar> dummy (n_components);

            const dealii::types::global_dof_index my_size = system_matrix.local_size();
            if (my_size > 0)
              {
                for (int ic=0; ic<n_components; ++ic)
                  {
                    TrilinosScalar *const begin = & (distributed_constant_modes[ic][0]);
                    TrilinosScalar *const end = begin + my_size;
                    std::fill (begin, end, 0);
                  }

                // here we assume constant FE among all cells
                const unsigned int dofs_per_cell = fe.dofs_per_cell;
                std::vector<dealii::types::global_dof_index> dof_indices (dofs_per_cell);

                typename DoFHandler<dim>::active_cell_iterator
                cell = dof_handler.begin_active();
                const typename DoFHandler<dim>::active_cell_iterator
                endc = dof_handler.end();
                for (; cell!=endc; ++cell)
                  if (cell->is_locally_owned())
                    {
                      cell->get_dof_indices (dof_indices);
                      for (unsigned int i=0; i<dofs_per_cell; ++i)
                        {
                          const unsigned int component_index
                            = cell->get_fe().system_to_component_index (i).first;
                          const long long int global_dof_index = dof_indices[i];
                          const int local_dof_index
                            = domain_map.LID (global_dof_index);
                          Assert (local_dof_index != -1,
                                  ExcMessage ("No access to DoF on remote processor!"));
                          distributed_constant_modes[component_index][local_dof_index] = 1;
                        }
                    }
                parameter_list.set ("null space: vectors",
                                    distributed_constant_modes.Values());
              }
            else
              {
                // We need to set a valid pointer to data even if there is no data on
                // the current processor. Therefore, pass a dummy in that case
                parameter_list.set ("null space: vectors", &dummy[0]);
              }
            preconditioner_ptr =
              new ML_Epetra::MultiLevelPreconditioner (matrix, parameter_list);
            Assert (preconditioner_ptr, ExcMessage ("Preconditioner setup failed."));
            break;
          }
          case Parameters::Solver::MDFILU:
          {
            std::cerr << "Initialize MDFILU\n";
            const unsigned estimated_row_length
              = 2 * system_matrix.n_nonzero_elements()/system_matrix.m();
            std::cerr << "n_nonzero_elements: " << system_matrix.n_nonzero_elements()
                      << std::endl;
            std::cerr << "system_matrix.m(): " << system_matrix.m()
                      << std::endl;
            preconditioner_ptr = new MDFILU (system_matrix,
                                             estimated_row_length,
                                             parameters->ILU_level);
            // Casting pointer type is not recommended, however here it is just
            // use for debug output.
            std::cerr << "number of new fill in: "
                      << static_cast<MDFILU *> (preconditioner_ptr)->number_of_new_fill_ins()
                      << std::endl;
            preconditioner_ptr->SetUseTranspose (false);
            std::cerr << "Start Iterate\n";
            break;
          }
          default:
          {
            AssertThrow (false, ExcMessage ("Preconditioner type not implemented."));
            break;
          }
          } //End of switch (parameters->prec_type)

        solver.SetUserMatrix (const_cast<Epetra_CrsMatrix *>
                              (&system_matrix.trilinos_matrix()));
        // SetUserMatrix will set up an internal preconditioner, switch
        // to user defined preconditioner when available.
        if (preconditioner_ptr)
          {
            solver.SetPrecOperator (preconditioner_ptr);
          }
        solver.Iterate (parameters->max_iterations, parameters->linear_residual);

        return_value.first = solver.NumIters();
        return_value.second = solver.TrueResidual();

        // Safety of deleting NULL pointer is assured by C++ standard
        delete preconditioner_ptr;
        preconditioner_ptr = 0;
        break;
        // End case Parameters::Solver::gmres:
      }
      default:
      {
        AssertThrow (false, ExcMessage ("Solver type not implemented."));
        break;
      }
      } // End switch (parameters->solver)

    return (return_value);
  }

#include "NSolver.inst"
}
<commit_msg>make preconditioner AMG run in parallel<commit_after>//
//  NSolver::solve.cpp
//
//  Created by Lei Qiao on 15/8/9.
//  A work based on deal.II tutorial step-33.
//

#include <NSolver/solver/NSolver.h>

namespace NSFEMSolver
{
  using namespace dealii;

  // @sect4{NSolver::solve}
  //
  // Here, we actually solve the linear system, using either of Trilinos'
  // Aztec or Amesos linear solvers. The result of the computation will be
  // written into the argument vector passed to this function. The result is a
  // pair of number of iterations and the final linear residual.

  template <int dim>
  std::pair<unsigned int, double>
  NSolver<dim>::solve (NSVector &newton_update)
  {
    std::pair<unsigned int, double> return_value (-1, -1);
    switch (parameters->solver)
      {
      // If the parameter file specified that a direct solver shall be used,
      // then we'll get here. The process is straightforward, since deal.II
      // provides a wrapper class to the Amesos direct solver within
      // Trilinos. All we have to do is to create a solver control object
      // (which is just a dummy object here, since we won't perform any
      // iterations), and then create the direct solver object. When
      // actually doing the solve, note that we don't pass a
      // preconditioner. That wouldn't make much sense for a direct solver
      // anyway.  At the end we return the solver control statistics —
      // which will tell that no iterations have been performed and that the
      // final linear residual is zero, absent any better information that
      // may be provided here:
      case Parameters::Solver::direct:
      {
        SolverControl solver_control (1,0);

        TrilinosWrappers::SolverDirect::AdditionalData
        solver_data (parameters->output == Parameters::Solver::verbose);
        TrilinosWrappers::SolverDirect direct (solver_control, solver_data);

        direct.solve (system_matrix, newton_update, right_hand_side);

        return_value.first = solver_control.last_step();
        return_value.second = solver_control.last_value();
        break;
      }

      // Likewise, if we are to use an iterative solver, we use Aztec's GMRES
      // solver. We could use the Trilinos wrapper classes for iterative
      // solvers and preconditioners here as well, but we choose to use an
      // Aztec solver directly. For the given problem, Aztec's internal
      // preconditioner implementations are superior over the ones deal.II has
      // wrapper classes to, so we use ILU-T preconditioning within the
      // AztecOO solver and set a bunch of options that can be changed from
      // the parameter file.
      //
      // There are two more practicalities: Since we have built our right hand
      // side and solution vector as deal.II Vector objects (as opposed to the
      // matrix, which is a Trilinos object), we must hand the solvers
      // Trilinos Epetra vectors.  Luckily, they support the concept of a
      // 'view', so we just send in a pointer to our deal.II vectors. We have
      // to provide an Epetra_Map for the vector that sets the parallel
      // distribution, which is just a dummy object in serial. The easiest way
      // is to ask the matrix for its map, and we're going to be ready for
      // matrix-vector products with it.
      //
      // Secondly, the Aztec solver wants us to pass a Trilinos
      // Epetra_CrsMatrix in, not the deal.II wrapper class itself. So we
      // access to the actual Trilinos matrix in the Trilinos wrapper class by
      // the command trilinos_matrix(). Trilinos wants the matrix to be
      // non-constant, so we have to manually remove the constantness using a
      // const_cast.
      case Parameters::Solver::gmres:
      {
        Epetra_Vector x (View, system_matrix.trilinos_matrix().DomainMap(),
                         newton_update.begin());
        Epetra_Vector b (View, system_matrix.trilinos_matrix().RangeMap(),
                         right_hand_side.begin());

        AztecOO solver;
        solver.SetAztecOption (AZ_output,
                               (parameters->output ==
                                Parameters::Solver::quiet
                                ?
                                AZ_none
                                :
                                AZ_all));
        solver.SetAztecOption (AZ_solver, AZ_gmres);
        solver.SetAztecOption (AZ_kspace, parameters->AZ_Krylov_space);
        solver.SetRHS (&b);
        solver.SetLHS (&x);

        Epetra_Operator *preconditioner_ptr (0);
        switch (parameters->prec_type)
          {
          case Parameters::Solver::NoPrec:
          {
            solver.SetAztecOption (AZ_precond, AZ_none);
            break;
          }
          case Parameters::Solver::AZ_DD:
          {
            solver.SetAztecOption (AZ_precond,  AZ_dom_decomp);
            solver.SetAztecOption (AZ_subdomain_solve, AZ_ilut);
            solver.SetAztecOption (AZ_overlap,  0);
            solver.SetAztecOption (AZ_reorder,  parameters->AZ_RCM_reorder);

            solver.SetAztecParam (AZ_drop,      parameters->ilut_drop);
            solver.SetAztecParam (AZ_ilut_fill, parameters->ilut_fill);
            solver.SetAztecParam (AZ_athresh,   parameters->ilut_atol);
            solver.SetAztecParam (AZ_rthresh,   parameters->ilut_rtol);
            break;
          }
          case Parameters::Solver::AZ_AMG:
          {
            // for parameter_list.set ("null space: dimension", int)
            const int n_components = EquationComponents<dim>::n_components;
            // Build the AMG preconditioner.
            Teuchos::ParameterList parameter_list;
            // Equation is not elliptic
            ML_Epetra::SetDefaults ("NSSA", parameter_list);
            parameter_list.set ("aggregation: type", "Uncoupled");
            parameter_list.set ("aggregation: block scaling", true);

            parameter_list.set ("smoother: type", "Chebyshev");
            parameter_list.set ("coarse: type", "Amesos-KLU");

            parameter_list.set ("smoother: sweeps", 2);
            parameter_list.set ("cycle applications", 1);
            // W-cycle
            // parameter_list.set ("prec type", "MGW");
            // V-cycle
            parameter_list.set ("prec type", "MGV");

            parameter_list.set ("smoother: Chebyshev alpha",10.);
            parameter_list.set ("smoother: ifpack overlap", 0);
            parameter_list.set ("aggregation: threshold", 1.0e-4);
            parameter_list.set ("coarse: max size", 2000);
            // No detail output
            parameter_list.set ("ML output", 0);

            parameter_list.set ("null space: type", "pre-computed");
            parameter_list.set ("null space: dimension", n_components);

            // Setup constant modes
            const Epetra_CrsMatrix &matrix = system_matrix.trilinos_matrix();
            const Epetra_Map &domain_map = matrix.OperatorDomainMap();

            Epetra_MultiVector distributed_constant_modes (domain_map, n_components);
            std::vector<TrilinosScalar> dummy (n_components);

            const dealii::types::global_dof_index my_size = system_matrix.local_size();
            if (my_size > 0)
              {
                for (int ic=0; ic<n_components; ++ic)
                  {
                    TrilinosScalar *const begin = & (distributed_constant_modes[ic][0]);
                    TrilinosScalar *const end = begin + my_size;
                    std::fill (begin, end, 0);
                  }

                // here we assume constant FE among all cells
                const unsigned int dofs_per_cell = fe.dofs_per_cell;
                std::vector<dealii::types::global_dof_index> dof_indices (dofs_per_cell);

                typename DoFHandler<dim>::active_cell_iterator
                cell = dof_handler.begin_active();
                const typename DoFHandler<dim>::active_cell_iterator
                endc = dof_handler.end();
                for (; cell!=endc; ++cell)
                  if (cell->is_locally_owned())
                    {
                      cell->get_dof_indices (dof_indices);
                      for (unsigned int i=0; i<dofs_per_cell; ++i)
                        {
                          const unsigned int component_index
                            = cell->get_fe().system_to_component_index (i).first;
                          const long long int global_dof_index = dof_indices[i];
                          const int local_dof_index = domain_map.LID (global_dof_index);
                          if (local_dof_index != -1)
                            {
                              // For locally owned DoFs
                              distributed_constant_modes[component_index][local_dof_index] = 1;
                            }
                        }
                    }
                parameter_list.set ("null space: vectors",
                                    distributed_constant_modes.Values());
              }
            else
              {
                // We need to set a valid pointer to data even if there is no data on
                // the current processor. Therefore, pass a dummy in that case
                parameter_list.set ("null space: vectors", &dummy[0]);
              }
            preconditioner_ptr =
              new ML_Epetra::MultiLevelPreconditioner (matrix, parameter_list);
            Assert (preconditioner_ptr, ExcMessage ("Preconditioner setup failed."));
            break;
          }
          case Parameters::Solver::MDFILU:
          {
            std::cerr << "Initialize MDFILU\n";
            const unsigned estimated_row_length
              = 2 * system_matrix.n_nonzero_elements()/system_matrix.m();
            std::cerr << "n_nonzero_elements: " << system_matrix.n_nonzero_elements()
                      << std::endl;
            std::cerr << "system_matrix.m(): " << system_matrix.m()
                      << std::endl;
            preconditioner_ptr = new MDFILU (system_matrix,
                                             estimated_row_length,
                                             parameters->ILU_level);
            // Casting pointer type is not recommended, however here it is just
            // use for debug output.
            std::cerr << "number of new fill in: "
                      << static_cast<MDFILU *> (preconditioner_ptr)->number_of_new_fill_ins()
                      << std::endl;
            preconditioner_ptr->SetUseTranspose (false);
            std::cerr << "Start Iterate\n";
            break;
          }
          default:
          {
            AssertThrow (false, ExcMessage ("Preconditioner type not implemented."));
            break;
          }
          } //End of switch (parameters->prec_type)

        solver.SetUserMatrix (const_cast<Epetra_CrsMatrix *>
                              (&system_matrix.trilinos_matrix()));
        // SetUserMatrix will set up an internal preconditioner, switch
        // to user defined preconditioner when available.
        if (preconditioner_ptr)
          {
            solver.SetPrecOperator (preconditioner_ptr);
          }
        solver.Iterate (parameters->max_iterations, parameters->linear_residual);

        return_value.first = solver.NumIters();
        return_value.second = solver.TrueResidual();

        // Safety of deleting NULL pointer is assured by C++ standard
        delete preconditioner_ptr;
        preconditioner_ptr = 0;
        break;
        // End case Parameters::Solver::gmres:
      }
      default:
      {
        AssertThrow (false, ExcMessage ("Solver type not implemented."));
        break;
      }
      } // End switch (parameters->solver)

    return (return_value);
  }

#include "NSolver.inst"
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QDebug>

#include <TelepathyQt4/Debug>

#include "qmessageglobal.h"
#include "qmessagemanager.h"
#include "qmessageaccount.h"
#include "qmessageaccountid.h"
#include "qmessageaccount_p.h"
#include "qmessageaccountfilter.h"
#include "qmessageaccountfilter_p.h"
#include "qmessageservice.h"
#include "qmessageservice_maemo6_p.h"
#include "qmessage_p.h"
#include "telepathyengine_maemo6_p.h"
#include "maemo6helpers_p.h"
#include "telepathyhelpers_maemo6_p.h"

Q_GLOBAL_STATIC(TelepathyEngine, telepathyEngine);

TelepathyEngine::TelepathyEngine():
        m_sync(true), m_error(QMessageManager::NoError)
{
    QDEBUG_FUNCTION_BEGIN
    Tp::registerTypes();
    Tp::enableDebug(false);
    Tp::enableWarnings(true);

    if (!(m_AM = Tp::AccountManager::create()))
        qWarning() << __FUNCTION__ << "Cannot create Account Manager (m_am)";
    else {
        connect(m_AM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)),
                SLOT(onAMReady(Tp::PendingOperation *)));
        connect(m_AM.data(), SIGNAL(accountCreated(const QString &)),
                SLOT(onAccountCreated(const QString &)));
    }

    m_CMName = CM_NAME_DEFAULT;

    if (m_sync)
        m_loop.exec(); // Loop locally untill accounts are initialized

    QDEBUG_FUNCTION_END
}

/*
bool TelepathyEngine::initialize()
{
    QDEBUG_FUNCTION_BEGIN
    bool ret = false;

    if (m_AM)
    {
        QObject::connect(m_AM->becomeReady(),SIGNAL(finished(Tp::PendingOperation *)),
            this, SLOT(onAMReady(Tp::PendingOperation *)));
        QObject::connect(m_AM.data(), SIGNAL(accountCreated(const QString &)),
            this, SLOT(onAccountCreated(const QString &)));
        ret = true;
    }

    QDEBUG_FUNCTION_END return ret;
}
*/
TelepathyEngine::~TelepathyEngine()
{

}

TelepathyEngine* TelepathyEngine::instance()
{
    TelepathyEngine* te = telepathyEngine();

    return te;
}

/******************************************************************/
/*                 PRIVATE SLOTS                                  */
/******************************************************************/
void TelepathyEngine::onAMReady(Tp::PendingOperation *op)
{
    QDEBUG_FUNCTION_BEGIN

    m_error = convertError(op);

    if (op && op->isError()) {
        qWarning() << "Account manager cannot become ready:" << op->errorName() << "-" << op->errorMessage();
        return;
    }

    TpSessionAccount *tpacc;

    foreach(const QString &path, m_AM->allAccountPaths()) {
        qDebug() << __FUNCTION__ << "found account";
        m_accounts += tpacc = new TpSessionAccount(m_AM, path);
        connect(tpacc, SIGNAL(accountReady(TpSessionAccount*)),
                SLOT(onAccountReady(TpSessionAccount *)));
    }

    // AccountManager is now ready
    qDebug() << "Valid accounts:";
    foreach(const QString &path, m_AM->validAccountPaths()) {
        qDebug() << " path:" << path;
    }

    QDEBUG_FUNCTION_END
}

/******************************************************************/

void TelepathyEngine::onAccountCreated(const QString &path)
{
    QDEBUG_FUNCTION_BEGIN
    qWarning() << "TelepathyEngine::onAccountCreated";
    m_accounts += new TpSessionAccount(m_AM, path);
    QDEBUG_FUNCTION_END
}

/******************************************************************/

void TelepathyEngine::onAccountReady(TpSessionAccount *tpacc)
{
    QDEBUG_FUNCTION_BEGIN
    qDebug() << "TpSession::onAccountReady:Account " << tpacc->acc->cmName() << "is Ready";

    connect(tpacc, SIGNAL(messageReceived(const Tp::ReceivedMessage &, TpSessionAccount *)),
            SLOT(onMessageReceived(const Tp::ReceivedMessage &, TpSessionAccount *)));

    if (!m_CMName.isEmpty() && tpacc->acc->cmName() == m_CMName) {
        if (m_sync) {
            m_sync = false;
            m_loop.quit();
        }

        emit accountReady(tpacc);
    }
    QDEBUG_FUNCTION_END
}

/******************************************************************/

void TelepathyEngine::onReady(Tp::PendingOperation *op)
{
    QDEBUG_FUNCTION_BEGIN
    m_error = convertError(op);
    QDEBUG_FUNCTION_END
};

/******************************************************************/

void TelepathyEngine::onMessageReceived(const Tp::ReceivedMessage &msg, TpSessionAccount *acc)
{
    QDEBUG_FUNCTION_BEGIN
    qDebug() << msg.text() << "from " << msg.sender()->id();

    emit messageReceived(msg, acc);
    QDEBUG_FUNCTION_END
}

/**
 * Returns pointer to TpSessionAccout object with specified connection manager or protocol, returns NULL if no match found
 *
 * \param cm  Name of the connection manager, if left empty matches every entry
 * \param protocol Name of the protocol manager, if left empty matches every entry
 */
TpSessionAccount *TelepathyEngine::getTpSessionAccount(const QString &cm, const QString &protocol)
{
    QDEBUG_FUNCTION_BEGIN
    qWarning() << "TelepathyEngine::getAccount" << cm << " " << protocol;

    foreach(TpSessionAccount *tpacc, m_accounts) {
        if ((!cm.isEmpty()  && tpacc->acc->cmName() == cm)
                || (!protocol.isEmpty() && tpacc->acc->protocol() == protocol)) {
            qWarning() << "TelepathyEngine::getAccount found" << tpacc->acc->cmName() << " " << tpacc->acc->protocol();
            QDEBUG_FUNCTION_END return tpacc;
        }
    }
    QDEBUG_FUNCTION_END return NULL;
}

bool TelepathyEngine::sendMessage(QMessage &message, QMessageService *service)
{
    QDEBUG_FUNCTION_BEGIN

    bool retVal(false);
    QMessage::Type type = message.type();
    QString cm = (type == QMessage::Sms) ? "ring" : (type == QMessage::InstantMessage) ? "gabble" : "";

    QMessageAccountId accountId = message.parentAccountId();

    qDebug() << __FUNCTION__ << "accountId: " << accountId.toString();

    if (!cm.isEmpty()) {
	if (TpSessionAccount *sessionAccount = getTpSessionAccount(cm)) {
	    SendRequest *request = new SendRequest(message, service);
	    retVal = sessionAccount->sendMessage(request);
	    if (!retVal) delete request;
	}
    } else {
        qWarning() << "TelepathyEngine::sendMessage : unsupported message type :" << type;
    }

    QDEBUG_FUNCTION_END

    return retVal;
}

void TelepathyEngine::_updateImAccounts() const
{
    QDEBUG_FUNCTION_BEGIN
    m_iAccounts.clear();

    foreach(TpSessionAccount *tpacc, m_accounts) {
        qDebug() << "TelepathyEngine::updateImAccounts" << tpacc->acc->cmName() << " protocol " << tpacc->acc->protocol() << " displayName " << tpacc->acc->displayName();
        bool account_ok = tpacc->acc->isEnabled() && tpacc->acc->isValidAccount();
        QString cm = tpacc->acc->cmName();

        qDebug() << "TelepathyEngine::updateImAccounts account_ok: " << account_ok << " isEnabled: " << tpacc->acc->isEnabled() << " isValidAccount: " << tpacc->acc->isValidAccount();

        if (account_ok) {
            if (cm == "ring") { // Ring connection manager for cellular telephony
                QString accountId = tpacc->acc->uniqueIdentifier();
                QString accountName = "SMS";
                QString accountAddress = "";
                QMessageAccount account = QMessageAccountPrivate::from(QMessageAccountId(accountId),
                                          accountName,
                                          QMessageAddress(QMessageAddress::Phone, accountAddress),
                                          QMessage::Sms);
                m_iAccounts.insert(accountId, account);
                m_defaultSmsAccountId = accountId;
                qDebug() << __FUNCTION__ << " Setting m_defaultSmsAccountId: " << m_defaultSmsAccountId.toString() << endl;
            } else if (cm == "gabble") { // Gabble for googletalk
                QString accountId = tpacc->acc->uniqueIdentifier();
                QString accountName = tpacc->acc->normalizedName();
                QString accountAddress = tpacc->acc->normalizedName();
                QMessageAccount account = QMessageAccountPrivate::from(QMessageAccountId(accountId),
                                          accountName,
                                          QMessageAddress(QMessageAddress::InstantMessage, accountAddress),
                                          QMessage::InstantMessage);
                m_iAccounts.insert(accountId, account);
            } else qWarning() << "Protocol " << tpacc->acc->protocol() << "with connectionmanager " << cm << "Is not yet supported";
//                if (strncmp(account_name_key, default_account, strlen(default_account))) iDefaultEmailAccountId = accountId;

        }
    }
    QDEBUG_FUNCTION_END
}

QMessageAccountIdList TelepathyEngine::queryAccounts(const QMessageAccountFilter &filter, const QMessageAccountSortOrder &sortOrder,
        uint limit, uint offset, bool &isFiltered, bool &isSorted)
{
    QDEBUG_FUNCTION_BEGIN
    Q_UNUSED(sortOrder);
    Q_UNUSED(limit);
    Q_UNUSED(offset);

    QMessageAccountIdList accountIds;
    m_error = QMessageManager::NoError;

    _updateImAccounts();
    foreach(QMessageAccount value, m_iAccounts) {
        accountIds.append(value.id());
    }

    MessagingHelper::filterAccounts(accountIds, filter);
    isFiltered = true;

    isSorted = false;

    QDEBUG_FUNCTION_END return accountIds;
}

int TelepathyEngine::countAccounts(const QMessageAccountFilter &filter)
{
    QDEBUG_FUNCTION_BEGIN
    bool isFiltered, isSorted;
    m_error = QMessageManager::NoError;
    QDEBUG_FUNCTION_END return queryAccounts(filter, QMessageAccountSortOrder(), 0, 0, isFiltered, isSorted).count();
}

QMessageAccount TelepathyEngine::account(const QMessageAccountId &id)
{
    QDEBUG_FUNCTION_BEGIN
    m_error = QMessageManager::NoError;
    _updateImAccounts();
    QDEBUG_FUNCTION_END return m_iAccounts[id.toString()];
}

QMessageAccountId TelepathyEngine ::defaultAccount(QMessage::Type type)
{
    QDEBUG_FUNCTION_BEGIN
    Q_UNUSED(type);

    m_error = QMessageManager::NoError;
    _updateImAccounts();
    return m_defaultSmsAccountId;
    QDEBUG_FUNCTION_END
}

QMessageManager::Error TelepathyEngine::convertError(const Tp::PendingOperation *op)
{
    if (op->isError())
        return QMessageManager::FrameworkFault ;

    if (!op->isValid())
        return QMessageManager::RequestIncomplete;

    return QMessageManager::NoError;
}

QMessageManager::Error TelepathyEngine ::error()
{
    return m_error;
}

#define TELEPATHY_ENGINE_STORE_MESSAGE

SendRequest::SendRequest(const QMessage &message, QMessageService *parent)
    : QObject(parent)
    , _message(message)
    , _pendingRequestCount(message.to().count())
    , _failCount(0)
{
#ifdef TELEPATHY_ENGINE_STORE_MESSAGE
    QMessagePrivate::setStandardFolder(_message, QMessage::DraftsFolder);
    if (!QMessageManager().addMessage(&_message)) {
	qWarning() << "SendRequest::SendRequest() : cannot add message";
    }
#endif
}

SendRequest::~SendRequest()
{
    qDebug() << "SendRequest::~SendRequest()";
}

QStringList SendRequest::to() const
{
    QStringList result;

    foreach (const QMessageAddress &address, _message.to()) {
	result << address.addressee();
    }

    return result;
}

QString SendRequest::text() const
{
    return _message.textContent();
}

void SendRequest::setFinished(const QString &address, bool success)
{
    if (!success) {
	_failCount++;
	qWarning() << "SendRequest::setFinished() : sending message to" << address << "failed";
    }
    down();
}

void SendRequest::finished(Tp::PendingOperation *operation, bool processLater)
{
    if (operation->isError()) {
	_failCount++;
	qWarning() << "SendRequest::finished() : " << operation->errorName() << ":" << operation->errorMessage();
    }

    if (processLater) {
	QTimer::singleShot(0, this, SLOT(down()));
    } else {
	down();
    }
}

void SendRequest::down()
{
    if (--_pendingRequestCount == 0) {
	QMessageService *service = qobject_cast<QMessageService *>(parent());
	if (service) {
	    QMessageServicePrivate *privateService = QMessageServicePrivate::implementation(*service);
	    bool success = (_failCount == 0);
#ifdef TELEPATHY_ENGINE_STORE_MESSAGE
	    if (success) {
		QMessagePrivate::setStandardFolder(_message, QMessage::SentFolder);
		if (!_message.id().isValid() || !QMessageManager().updateMessage(&_message)) {
		    qWarning() << "SendRequest::down() : cannot update message";
		}
	    }
#endif
	    privateService->setFinished(success);
	}
	deleteLater();
    }
}

<commit_msg>Check pointer before using it (Written by Niklas Kurkisuo)<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QDebug>

#include <TelepathyQt4/Debug>

#include "qmessageglobal.h"
#include "qmessagemanager.h"
#include "qmessageaccount.h"
#include "qmessageaccountid.h"
#include "qmessageaccount_p.h"
#include "qmessageaccountfilter.h"
#include "qmessageaccountfilter_p.h"
#include "qmessageservice.h"
#include "qmessageservice_maemo6_p.h"
#include "qmessage_p.h"
#include "telepathyengine_maemo6_p.h"
#include "maemo6helpers_p.h"
#include "telepathyhelpers_maemo6_p.h"

Q_GLOBAL_STATIC(TelepathyEngine, telepathyEngine);

TelepathyEngine::TelepathyEngine():
        m_sync(true), m_error(QMessageManager::NoError)
{
    QDEBUG_FUNCTION_BEGIN
    Tp::registerTypes();
    Tp::enableDebug(false);
    Tp::enableWarnings(true);

    if (!(m_AM = Tp::AccountManager::create()))
        qWarning() << __FUNCTION__ << "Cannot create Account Manager (m_am)";
    else {
        connect(m_AM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)),
                SLOT(onAMReady(Tp::PendingOperation *)));
        connect(m_AM.data(), SIGNAL(accountCreated(const QString &)),
                SLOT(onAccountCreated(const QString &)));
    }

    m_CMName = CM_NAME_DEFAULT;

    if (m_sync)
        m_loop.exec(); // Loop locally untill accounts are initialized

    QDEBUG_FUNCTION_END
}

/*
bool TelepathyEngine::initialize()
{
    QDEBUG_FUNCTION_BEGIN
    bool ret = false;

    if (m_AM)
    {
        QObject::connect(m_AM->becomeReady(),SIGNAL(finished(Tp::PendingOperation *)),
            this, SLOT(onAMReady(Tp::PendingOperation *)));
        QObject::connect(m_AM.data(), SIGNAL(accountCreated(const QString &)),
            this, SLOT(onAccountCreated(const QString &)));
        ret = true;
    }

    QDEBUG_FUNCTION_END return ret;
}
*/
TelepathyEngine::~TelepathyEngine()
{

}

TelepathyEngine* TelepathyEngine::instance()
{
    TelepathyEngine* te = telepathyEngine();

    return te;
}

/******************************************************************/
/*                 PRIVATE SLOTS                                  */
/******************************************************************/
void TelepathyEngine::onAMReady(Tp::PendingOperation *op)
{
    QDEBUG_FUNCTION_BEGIN

    m_error = convertError(op);

    if (op && op->isError()) {
        qWarning() << "Account manager cannot become ready:" << op->errorName() << "-" << op->errorMessage();
        return;
    }

    TpSessionAccount *tpacc;

    foreach(const QString &path, m_AM->allAccountPaths()) {
        qDebug() << __FUNCTION__ << "found account";
        m_accounts += tpacc = new TpSessionAccount(m_AM, path);
        connect(tpacc, SIGNAL(accountReady(TpSessionAccount*)),
                SLOT(onAccountReady(TpSessionAccount *)));
    }

    // AccountManager is now ready
    qDebug() << "Valid accounts:";
    foreach(const QString &path, m_AM->validAccountPaths()) {
        qDebug() << " path:" << path;
    }

    QDEBUG_FUNCTION_END
}

/******************************************************************/

void TelepathyEngine::onAccountCreated(const QString &path)
{
    QDEBUG_FUNCTION_BEGIN
    qWarning() << "TelepathyEngine::onAccountCreated";
    m_accounts += new TpSessionAccount(m_AM, path);
    QDEBUG_FUNCTION_END
}

/******************************************************************/

void TelepathyEngine::onAccountReady(TpSessionAccount *tpacc)
{
    QDEBUG_FUNCTION_BEGIN
    qDebug() << "TpSession::onAccountReady:Account " << tpacc->acc->cmName() << "is Ready";

    connect(tpacc, SIGNAL(messageReceived(const Tp::ReceivedMessage &, TpSessionAccount *)),
            SLOT(onMessageReceived(const Tp::ReceivedMessage &, TpSessionAccount *)));

    if (!m_CMName.isEmpty() && tpacc->acc->cmName() == m_CMName) {
        if (m_sync) {
            m_sync = false;
            m_loop.quit();
        }

        emit accountReady(tpacc);
    }
    QDEBUG_FUNCTION_END
}

/******************************************************************/

void TelepathyEngine::onReady(Tp::PendingOperation *op)
{
    QDEBUG_FUNCTION_BEGIN
    m_error = convertError(op);
    QDEBUG_FUNCTION_END
};

/******************************************************************/

void TelepathyEngine::onMessageReceived(const Tp::ReceivedMessage &msg, TpSessionAccount *acc)
{
    QDEBUG_FUNCTION_BEGIN
    qDebug() << msg.text() << "from " << msg.sender()->id();

    emit messageReceived(msg, acc);
    QDEBUG_FUNCTION_END
}

/**
 * Returns pointer to TpSessionAccout object with specified connection manager or protocol, returns NULL if no match found
 *
 * \param cm  Name of the connection manager, if left empty matches every entry
 * \param protocol Name of the protocol manager, if left empty matches every entry
 */
TpSessionAccount *TelepathyEngine::getTpSessionAccount(const QString &cm, const QString &protocol)
{
    QDEBUG_FUNCTION_BEGIN
    qWarning() << "TelepathyEngine::getAccount" << cm << " " << protocol;

    foreach(TpSessionAccount *tpacc, m_accounts) {
        if ((!cm.isEmpty()  && tpacc->acc->cmName() == cm)
                || (!protocol.isEmpty() && tpacc->acc->protocol() == protocol)) {
            qWarning() << "TelepathyEngine::getAccount found" << tpacc->acc->cmName() << " " << tpacc->acc->protocol();
            QDEBUG_FUNCTION_END return tpacc;
        }
    }
    QDEBUG_FUNCTION_END return NULL;
}

bool TelepathyEngine::sendMessage(QMessage &message, QMessageService *service)
{
    QDEBUG_FUNCTION_BEGIN

    bool retVal(false);
    QMessage::Type type = message.type();
    QString cm = (type == QMessage::Sms) ? "ring" : (type == QMessage::InstantMessage) ? "gabble" : "";

    QMessageAccountId accountId = message.parentAccountId();

    qDebug() << __FUNCTION__ << "accountId: " << accountId.toString();

    if (!cm.isEmpty()) {
	if (TpSessionAccount *sessionAccount = getTpSessionAccount(cm)) {
	    SendRequest *request = new SendRequest(message, service);
	    retVal = sessionAccount->sendMessage(request);
	    if (!retVal) delete request;
	}
    } else {
        qWarning() << "TelepathyEngine::sendMessage : unsupported message type :" << type;
    }

    QDEBUG_FUNCTION_END

    return retVal;
}

void TelepathyEngine::_updateImAccounts() const
{
    QDEBUG_FUNCTION_BEGIN
    m_iAccounts.clear();

    foreach(TpSessionAccount *tpacc, m_accounts) {
        qDebug() << "TelepathyEngine::updateImAccounts" << tpacc->acc->cmName() << " protocol " << tpacc->acc->protocol() << " displayName " << tpacc->acc->displayName();
        bool account_ok = tpacc->acc->isEnabled() && tpacc->acc->isValidAccount();
        QString cm = tpacc->acc->cmName();

        qDebug() << "TelepathyEngine::updateImAccounts account_ok: " << account_ok << " isEnabled: " << tpacc->acc->isEnabled() << " isValidAccount: " << tpacc->acc->isValidAccount();

        if (account_ok) {
            if (cm == "ring") { // Ring connection manager for cellular telephony
                QString accountId = tpacc->acc->uniqueIdentifier();
                QString accountName = "SMS";
                QString accountAddress = "";
                QMessageAccount account = QMessageAccountPrivate::from(QMessageAccountId(accountId),
                                          accountName,
                                          QMessageAddress(QMessageAddress::Phone, accountAddress),
                                          QMessage::Sms);
                m_iAccounts.insert(accountId, account);
                m_defaultSmsAccountId = accountId;
                qDebug() << __FUNCTION__ << " Setting m_defaultSmsAccountId: " << m_defaultSmsAccountId.toString() << endl;
            } else if (cm == "gabble") { // Gabble for googletalk
                QString accountId = tpacc->acc->uniqueIdentifier();
                QString accountName = tpacc->acc->normalizedName();
                QString accountAddress = tpacc->acc->normalizedName();
                QMessageAccount account = QMessageAccountPrivate::from(QMessageAccountId(accountId),
                                          accountName,
                                          QMessageAddress(QMessageAddress::InstantMessage, accountAddress),
                                          QMessage::InstantMessage);
                m_iAccounts.insert(accountId, account);
            } else qWarning() << "Protocol " << tpacc->acc->protocol() << "with connectionmanager " << cm << "Is not yet supported";
//                if (strncmp(account_name_key, default_account, strlen(default_account))) iDefaultEmailAccountId = accountId;

        }
    }
    QDEBUG_FUNCTION_END
}

QMessageAccountIdList TelepathyEngine::queryAccounts(const QMessageAccountFilter &filter, const QMessageAccountSortOrder &sortOrder,
        uint limit, uint offset, bool &isFiltered, bool &isSorted)
{
    QDEBUG_FUNCTION_BEGIN
    Q_UNUSED(sortOrder);
    Q_UNUSED(limit);
    Q_UNUSED(offset);

    QMessageAccountIdList accountIds;
    m_error = QMessageManager::NoError;

    _updateImAccounts();
    foreach(QMessageAccount value, m_iAccounts) {
        accountIds.append(value.id());
    }

    MessagingHelper::filterAccounts(accountIds, filter);
    isFiltered = true;

    isSorted = false;

    QDEBUG_FUNCTION_END return accountIds;
}

int TelepathyEngine::countAccounts(const QMessageAccountFilter &filter)
{
    QDEBUG_FUNCTION_BEGIN
    bool isFiltered, isSorted;
    m_error = QMessageManager::NoError;
    QDEBUG_FUNCTION_END return queryAccounts(filter, QMessageAccountSortOrder(), 0, 0, isFiltered, isSorted).count();
}

QMessageAccount TelepathyEngine::account(const QMessageAccountId &id)
{
    QDEBUG_FUNCTION_BEGIN
    m_error = QMessageManager::NoError;
    _updateImAccounts();
    QDEBUG_FUNCTION_END return m_iAccounts[id.toString()];
}

QMessageAccountId TelepathyEngine ::defaultAccount(QMessage::Type type)
{
    QDEBUG_FUNCTION_BEGIN
    Q_UNUSED(type);

    m_error = QMessageManager::NoError;
    _updateImAccounts();
    return m_defaultSmsAccountId;
    QDEBUG_FUNCTION_END
}

QMessageManager::Error TelepathyEngine::convertError(const Tp::PendingOperation *op)
{
    if (!op || op->isError())
        return QMessageManager::FrameworkFault ;

    if (!op->isValid())
        return QMessageManager::RequestIncomplete;

    return QMessageManager::NoError;
}

QMessageManager::Error TelepathyEngine ::error()
{
    return m_error;
}

#define TELEPATHY_ENGINE_STORE_MESSAGE

SendRequest::SendRequest(const QMessage &message, QMessageService *parent)
    : QObject(parent)
    , _message(message)
    , _pendingRequestCount(message.to().count())
    , _failCount(0)
{
#ifdef TELEPATHY_ENGINE_STORE_MESSAGE
    QMessagePrivate::setStandardFolder(_message, QMessage::DraftsFolder);
    if (!QMessageManager().addMessage(&_message)) {
	qWarning() << "SendRequest::SendRequest() : cannot add message";
    }
#endif
}

SendRequest::~SendRequest()
{
    qDebug() << "SendRequest::~SendRequest()";
}

QStringList SendRequest::to() const
{
    QStringList result;

    foreach (const QMessageAddress &address, _message.to()) {
	result << address.addressee();
    }

    return result;
}

QString SendRequest::text() const
{
    return _message.textContent();
}

void SendRequest::setFinished(const QString &address, bool success)
{
    if (!success) {
	_failCount++;
	qWarning() << "SendRequest::setFinished() : sending message to" << address << "failed";
    }
    down();
}

void SendRequest::finished(Tp::PendingOperation *operation, bool processLater)
{
    if (operation->isError()) {
	_failCount++;
	qWarning() << "SendRequest::finished() : " << operation->errorName() << ":" << operation->errorMessage();
    }

    if (processLater) {
	QTimer::singleShot(0, this, SLOT(down()));
    } else {
	down();
    }
}

void SendRequest::down()
{
    if (--_pendingRequestCount == 0) {
	QMessageService *service = qobject_cast<QMessageService *>(parent());
	if (service) {
	    QMessageServicePrivate *privateService = QMessageServicePrivate::implementation(*service);
	    bool success = (_failCount == 0);
#ifdef TELEPATHY_ENGINE_STORE_MESSAGE
	    if (success) {
		QMessagePrivate::setStandardFolder(_message, QMessage::SentFolder);
		if (!_message.id().isValid() || !QMessageManager().updateMessage(&_message)) {
		    qWarning() << "SendRequest::down() : cannot update message";
		}
	    }
#endif
	    privateService->setFinished(success);
	}
	deleteLater();
    }
}

<|endoftext|>


<commit_before>/*
* Copyright 2010-2011 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "stdafx.h"
#include "BuildServerManager.h"
#include "PortScanner.h"
#ifdef Q_WS_WIN
#include <windows.h>
#endif

BuildServerManager* BuildServerManager::_instance = 0;

BuildServerManager::BuildServerManager()
{
    _serverProcess = new QProcess(this);
    connect(_serverProcess, SIGNAL(started()), this, SLOT(serverStarted()));
    connect(_serverProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError)));
    connect(_serverProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStdOutput()));
    connect(_serverProcess, SIGNAL(readyReadStandardError()), this, SLOT(readStdError()));
}

BuildServerManager::~BuildServerManager(void)
{
}

BuildServerManager* BuildServerManager::getInstance()
{
    if ( _instance == 0 )
        _instance = new BuildServerManager();
    return _instance;
}

unsigned short BuildServerManager::start(QString server, int port)
{
    unsigned short serverPort = 0;
    QStringList arguments = server.split(" ");
    QString portStr;

    portStr.setNum(validatePort(port));
    arguments.replaceInStrings(QString("$PORT"), portStr);

    QFile command(server);

    server = arguments[0];
    QDir dir = server;
    server = dir.absolutePath();
    arguments.removeAt(0);
    arguments.join("");
#ifdef Q_WS_WIN
    server.append(".exe");
#endif

    QString tempDir = "/tmp";

#ifdef Q_WS_WIN
    tempDir = getenv("TEMP");
#endif

    QFile pidFile(tempDir + QString("/rbd_service.pid"));

    if (pidFile.open(QIODevice::ReadWrite | QIODevice::Text))
    {
        QString s_pidInfo = pidFile.readLine();

        if (s_pidInfo.split(";").length() > 1)
            serverPort = s_pidInfo.split(";")[1].toUInt();

        unsigned int pid = s_pidInfo.split(";")[0].toUInt();
#ifdef Q_WS_WIN
        HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
        CloseHandle(process);
#else
        process = 0; // port is free, launch new proces
#endif
        if (process == 0)
        {
            _serverProcess->start(server, arguments);
            pidFile.close();
            pidFile.open(QIODevice::WriteOnly | QIODevice::Text);
            QString pidInfo = QString::number((int)_serverProcess->pid() + ";" + portStr;
            pidFile.write(pidInfo.toAscii());
            pidFile.close();
        }
    }

    return serverPort;
}

void BuildServerManager::stop()
{
    if ( _serverProcess )
        _serverProcess->close();
    delete _instance;
    _instance = 0;
}

int BuildServerManager::validatePort(int port)
{
    PortScanner scanner;
    int usablePort = scanner.findUsablePort( (unsigned short)port);
    emit findUsablePort(usablePort);
    return usablePort;
}

void BuildServerManager::serverStarted()
{
    qDebug() << "Build Server started";
}

void BuildServerManager::onError(QProcess::ProcessError err)
{
    if ( err == QProcess::Crashed )
        qDebug() << "Server is killed by Ripple";
    else
        qDebug() << "Build Server can not be started. Error code: " << err;
}

void BuildServerManager::readStdOutput()
{
    qDebug() << _serverProcess->readAllStandardOutput();
}

void BuildServerManager::readStdError()
{
    qDebug() << _serverProcess->readAllStandardError();
}<commit_msg>Fixed typo again.. compile now works<commit_after>/*
* Copyright 2010-2011 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "stdafx.h"
#include "BuildServerManager.h"
#include "PortScanner.h"
#ifdef Q_WS_WIN
#include <windows.h>
#endif

BuildServerManager* BuildServerManager::_instance = 0;

BuildServerManager::BuildServerManager()
{
    _serverProcess = new QProcess(this);
    connect(_serverProcess, SIGNAL(started()), this, SLOT(serverStarted()));
    connect(_serverProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError)));
    connect(_serverProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStdOutput()));
    connect(_serverProcess, SIGNAL(readyReadStandardError()), this, SLOT(readStdError()));
}

BuildServerManager::~BuildServerManager(void)
{
}

BuildServerManager* BuildServerManager::getInstance()
{
    if ( _instance == 0 )
        _instance = new BuildServerManager();
    return _instance;
}

unsigned short BuildServerManager::start(QString server, int port)
{
    unsigned short serverPort = 0;
    QStringList arguments = server.split(" ");
    QString portStr;

    portStr.setNum(validatePort(port));
    arguments.replaceInStrings(QString("$PORT"), portStr);

    QFile command(server);

    server = arguments[0];
    QDir dir = server;
    server = dir.absolutePath();
    arguments.removeAt(0);
    arguments.join("");
#ifdef Q_WS_WIN
    server.append(".exe");
#endif

    QString tempDir = "/tmp";

#ifdef Q_WS_WIN
    tempDir = getenv("TEMP");
#endif

    QFile pidFile(tempDir + QString("/rbd_service.pid"));

    if (pidFile.open(QIODevice::ReadWrite | QIODevice::Text))
    {
        QString s_pidInfo = pidFile.readLine();

        if (s_pidInfo.split(";").length() > 1)
            serverPort = s_pidInfo.split(";")[1].toUInt();

        unsigned int pid = s_pidInfo.split(";")[0].toUInt();
#ifdef Q_WS_WIN
        HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
        CloseHandle(process);
#else
        process = 0; // port is free, launch new proces
#endif
        if (process == 0)
        {
            _serverProcess->start(server, arguments);
            pidFile.close();
            pidFile.open(QIODevice::WriteOnly | QIODevice::Text);
            QString pidInfo = QString::number((int)_serverProcess->pid()) + ";" + portStr;
            pidFile.write(pidInfo.toAscii());
            pidFile.close();
        }
    }

    return serverPort;
}

void BuildServerManager::stop()
{
    if ( _serverProcess )
        _serverProcess->close();
    delete _instance;
    _instance = 0;
}

int BuildServerManager::validatePort(int port)
{
    PortScanner scanner;
    int usablePort = scanner.findUsablePort( (unsigned short)port);
    emit findUsablePort(usablePort);
    return usablePort;
}

void BuildServerManager::serverStarted()
{
    qDebug() << "Build Server started";
}

void BuildServerManager::onError(QProcess::ProcessError err)
{
    if ( err == QProcess::Crashed )
        qDebug() << "Server is killed by Ripple";
    else
        qDebug() << "Build Server can not be started. Error code: " << err;
}

void BuildServerManager::readStdOutput()
{
    qDebug() << _serverProcess->readAllStandardOutput();
}

void BuildServerManager::readStdError()
{
    qDebug() << _serverProcess->readAllStandardError();
}<|endoftext|>