Signal-Slot makes a mess - c++

I am trying to create a image-saving application using Qt. Now the stub
class ImageSaver:public QObject
{
int index;
QWebPage * main_Page;
QNetworkAccessManager * manager;
QNetworkReply * reply;
QString file_Name;
QSet<QString> image_Addresses;
QString web_Address;
Q_OBJECT
signals:
void image_Saved();
public slots:
void request_Image();
void on_Finished(bool status);
void got_Reply(QNetworkReply * reply);
public:
ImageSaver();
void start();
};
ImageSaver::ImageSaver()
{
index = 0;
manager = new QNetworkAccessManager;
reply = NULL;
connect(main_Page,SIGNAL(loadFinished(bool)),this,SLOT(on_Finished(bool)));
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(got_Reply(QNetworkReply*)));
connect(this,SIGNAL(image_Saved()),this,SLOT(request_Image()));
}
void ImageSaver::start()
{
//loads the url
// In the end of the loading it will emit load_Finished(bool)
// So that signal will execute on_Finished(bool)
}
void ImageSaver::request_Image()
{
QString temp_Address = *(image_Addresses.begin()+index);
//makes a request to the server to give the image "temp_Address"
//When the server gives the reply signal finished(QNetworkReply*) will be emitted
// this in turn will call the got_Reply(QNetworkReply*)
}
void ImageSaver::on_Finished(bool status)
{
//collects all the images's url addresses, and pushes them in the list
//"image_Addresses"
//Then emits image_Saved();
//This signal will wake up the function request_Image()
}
void ImageSaver::got_Reply(QNetworkReply * reply)
{
//Image is extracted from the reply and got saved in the same name as in the page
//index got increased;
//emits the signal image_Saved();
//This signal will activate the function request_Image()
}
int main(int argc,char * argv[])
{
QApplication app(argc,argv);
ImageSaver a;
a.start();
return app.exec();
}
#include "main.moc"
In short First call is to "start".That calls "on_Finished" and there is no problem untill this. So all the image files's addresses got pushed in the list. Next is one by one request for image[i] made, and the reply image got saved. This thing is happening repeatedly. Here only I am getting problem. Crashes are appearing in this operation especially in saving the image.
My assumption is "signal-slot" is not like function call, thy are more or less like thread but operates on the same function( pointer). So when one signal requests for painter, which is already rendering something then the crash will appear.
Can anybody say the fact behind the crash and how to save all the images without crash?
EDIT:
Hi, This is the full code. Run this one, and click the message boxes contineously
#include <QApplication>
#include <QDir>
#include <QImage>
#include <QObject>
#include <QMessageBox>
#include <QPainter>
#include <QPixmap>
#include <QSet>
#include <QTimer>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QtWebKit/QWebElement>
#include <QtWebKit/QWebFrame>
#include <QtWebKit/QWebPage>
#include <QUrl>
class ImageSaver:public QObject
{
int index;
QWebPage * main_Page;
QNetworkAccessManager * manager;
QNetworkReply * reply;
QString file_Name;
QSet<QString> image_Addresses;
QString web_Address;
Q_OBJECT
signals:
void image_Saved();
public slots:
void request_Image();
void on_Finished(bool status);
void got_Reply(QNetworkReply * reply);
public:
ImageSaver();
void start();
protected:
//void show_Frame(QWebFrame * frame);
};
ImageSaver::ImageSaver()
{
index = 0;
this->main_Page = new QWebPage;
manager = new QNetworkAccessManager;
reply = NULL;
connect(main_Page,SIGNAL(loadFinished(bool)),this,SLOT(on_Finished(bool)));
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(got_Reply(QNetworkReply*)));
connect(this,SIGNAL(image_Saved()),this,SLOT(request_Image()));
}
void ImageSaver::start()
{
web_Address = "yahoo.com";
QDir dir;
dir.mkdir(web_Address);
QUrl url = QUrl::fromUserInput(web_Address);
main_Page->mainFrame()->load(url);
}
void ImageSaver::request_Image()
{
QString temp_Address = *(image_Addresses.begin()+index);
int a = temp_Address.lastIndexOf("/");
file_Name = temp_Address.mid(a+1);
//Without the below message box, the program closes shortly
//This message box is slowing down that effect
QMessageBox hh;
hh.setText(file_Name);
hh.exec();
QNetworkRequest request= QNetworkRequest(QUrl(temp_Address));
request.setRawHeader("img","src");
manager->get(request);
}
void ImageSaver::on_Finished(bool status)
{
if(status)
{
QMessageBox mm;
mm.setText("Finished");
mm.exec();
QWebElementCollection temp_Collection= main_Page->mainFrame()->findAllElements("*");
for(int i=0;i<temp_Collection.count();++i)
{
QWebElement temp_Element = temp_Collection[i];
if(temp_Element.tagName().contains("img",Qt::CaseInsensitive) && temp_Element.attributeNames().contains("src",Qt::CaseInsensitive))
{
QString image_Web_Address = temp_Element.attribute("src");
if(!image_Addresses.contains(image_Web_Address))
image_Addresses.insert(image_Web_Address);
}
}
emit image_Saved();
QMessageBox kk;
kk.setText("Image is going to be saved");
kk.exec();
}
else
{
QMessageBox mm;
mm.setText("Not ready");
mm.exec();
}
QMessageBox mm;
mm.setText("Getting out of finished");
mm.exec();
}
void ImageSaver::got_Reply(QNetworkReply * reply)
{
QImage image;
if(image.load(static_cast<QIODevice *>(reply),0))
image.save(web_Address+QDir::separator()+file_Name,0);
++index;
emit image_Saved();
}
/*
void ImageSaver::show_Frame(QWebFrame * temp_Frame)
{
QImage image(temp_Frame->contentsSize(),QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::transparent);
QPainter painter(&image);
painter.setRenderHint(QPainter::Antialiasing,true);
painter.setRenderHint(QPainter::TextAntialiasing,true);
painter.setRenderHint(QPainter::SmoothPixmapTransform,true);
temp_Frame->documentElement().render(&painter);
painter.end();
foreach(QWebFrame * temp_Frame0,temp_Frame->childFrames())
show_Frame(temp_Frame0);
}
*/
int main(int argc,char * argv[])
{
QApplication app(argc,argv);
ImageSaver a;
a.start();
return app.exec();
}
#include "main.moc"
This is the pro file
QT += webkit network
SOURCES += \
main.cpp

Your code crashes because you read beyond the boundaries of the image_Addresses set.
void ImageSaver::request_Image()
{
QString temp_Address = *(image_Addresses.begin()+index);
...
You increment index after every image received, but there isn't any check anywhere in the code whether index is still less than image_Addresses.size(), so it crashes once dereferencing image_Addresses.begin()+index for index == image_Addresses.size().

There may be many solutions to this problem. I think that you should have a look at The State Machine Framework. In easy situations you can just use boolean variable to check if you can go on. You should also think what to do when you're busy processing the image. You can queue request or just reject them. Also you can implement threading, so that new requests are served by new threads.
P.S. Signals are more like events than threads to me.

What's the error and why do you have a #include at the end?
FYI there is a QImage class you can use instead which includes saving and loading from a QIODevice* such as QNetworkReply for example. It's extremely rare to need to reinvent the wheel in the massive framework that is Qt.

Related

Multiple get/post calls using a wrapper class with Qt

I am working on a Qt project with a team. I have two functions — one retrives the numerical coordinates of a place, the other downloads the map of the place — that I want to merge in one wrapper class, so that my teammates can call it easily.
#include <QCoreApplication>
#include <QFile>
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <iostream>
class OpenStreetMapWrapper: public QObject{
Q_OBJECT
public:
OpenStreetMapWrapper(QObject *parent=nullptr):QObject(parent){
connect(&manager, &QNetworkAccessManager::finished, this, &OpenStreetMapWrapper::handle_finished);
}
void download(const std::string &region, const std::string &department, const QFile& outfile){
QNetworkRequest request;
QUrl url = QUrl(QString::fromStdString("https://download.openstreetmap.fr/extracts/europe/france/" + region + "/" + department + ".osm.pbf"));
request.setUrl(url);
request.setAttribute(QNetworkRequest::User, outfile.fileName());
manager.get(request);
}
void searchCSV(QFile& file, QFile& outfile){
QNetworkRequest request(QUrl("https://api-adresse.data.gouv.fr/search/csv/")); // Free API provided by the French government
request.setAttribute(QNetworkRequest::User, outfile.fileName());
QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart postpart;
postpart.setHeader(QNetworkRequest::ContentDispositionHeader,
QString("form-data; name=%1; filename=%2")
.arg("data", file.fileName()));
postpart.setBodyDevice(&file);
multipart->append(postpart);
file.setParent(multipart);
manager.post(request, multipart);
}
private:
QNetworkAccessManager manager;
void handle_finished(QNetworkReply *reply){
if(reply->error() == QNetworkReply::NoError){
QByteArray read = reply->readAll();
std::cout << read.toStdString() << std::endl; // For debugging
QString filename = reply->request().attribute(QNetworkRequest::User).toString();
QFile out(filename);
if(out.open(QIODevice::WriteOnly)){
out.write(read);
out.close();
}
}
else{
qDebug() << reply->error() << reply->errorString();
}
reply->deleteLater();
// QCoreApplication::quit(); This is done somewhere else?
}
};
#include <main.moc>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
OpenStreetMapWrapper A;
QFile file("./search.csv");
file.open(QIODevice::ReadWrite);
QFile outfile("./output.csv");
outfile.open(QIODevice::ReadWrite);
// Search
A.searchCSV(file, outfile); // 1st call works
A.searchCSV(file, outfile); // 2nd call -> makes both calls fail.
// Downloader
std::string region = "corse";
std::string department = "haute_corse";
return a.exec();
}
The problem with the code above, is that when for example searchCSV is called it displays the output as needed, but if it is called twice in the code, there is no output at all. After some debugging I think the problem is that the manager and handle_finished are not connected properly, because the execution never reaches there. Is there a simple way to solve this issue? Ideally, there is just one class instant, and any method can be called any number of times.
I don't know much about Qt, but it looks like you're trying to read from file twice and my guess is that when it reaches the end of the file after the first call to A.searchCSV it is done and you can't read from it anymore - unless you reposition the QFile to the beginning of the file.
Possible solution:
A.searchCSV(file, outfile);
file.unsetError(); // possibly needed
file.seek(0); // rewind to the start of the file
A.searchCSV(file, outfile);
The two QFile (input, output) are shared between two asynchronous calls (searchCSV) that might give an undefined behavior. The input file (stream) contents will be load and push only after the connection was made (like curl does).
You should:
Make searchCSV a blocking function (wait until handle_finished() done), input file pointer should be reinitialized before an other call.
OR: Use separated input/output QFile instances

Stop qt application in infinite loop when main window is closed

My main application class is USB_Packet_Analyzer which processes some files, but also supports reading from a file to which somebody still writes. In that case, I have an infinity loop which checks whether something new was written in this file and if so, I continue in processing. In every iteration of loop I am calling QCoreApplication::processEvents();.
The problem is that when I close main window of app, it wont stop the application. If I check QApplication::topLevelWidgets().size() it is still 1, and QApplication::topLevelWidgets().at(0)->isVisible() is false. Why isn't it closing my window? Can I connect some signal to detect whether red cross on window was clicked or not? I know that when getting into this kind of loops i might use QThread, but I'd rather not get this involved. Is there any solution for my problem?
Take a look at the QFileSystemWatcher Class and its fileChanged signal.
#include <QFileSystemWatcher>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
private:
QFileSystemWatcher* fileWatcher;
Ui::MainWindow*ui;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
createUi();
fileWatcher = new QFileSystemWatcher(this);
connect(fileWatcher, SIGNAL(fileChanged(QString)), this, SLOT(fileChangedSlot(QString)));
QFileInfo file("file_to_watch.txt");
if (file.exists())
{
fileWatcher->addPath(file.absoluteFilePath());
}
}
void MainWindow::fileChangedSlot(const QString &path)
{
if (fileWatcher->files().contains(path))
{
qDebug() << "File changed" << path;
}
}
You can using of system interrupt signal to manage a Boolean to breaking your infinite loop or exiting the application.
e.g:
#include <iostream>
#include <csignal>
using namespace std;
void InterruptSignalHandler(int signal_number) {
cout<< "Signal Number is "<<signal_number<<endl;
exit(signal_number);
}
int main()
{
signal(SIGINT, InterruptSignalHandler);
string a;
while(true)
{
cout<<">";
cin >> a;
}
return 0;
}

Looping through QNetworkAccessManager get() routines, retrieve order on finish

I have a QNetworkAccessManager as a member of my class. I connect the finished signal from this manager to the replyFinished function I have written.
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*)));
In a separate routine, I loop through a get call from the manager
for (int si = 0; si<numLines; si++)
{
QString line = lines[si];
manager->get(QNetworkRequest(QUrl(line)));
}
In my replyFinished slot routine, I know I may not receive the signals in the order they were performed in the loop, but is there any way I can obtain that information? That is, is there a clever way I can obtain "si" in my replyFinished routine? Thanks for the help!
QNetworkAccessManager::get() returns a pointer to the QNetworkReply object. This pointer is the same one that is passed your replyFinished() slot. You can use a QMap to store pairings of QNetworkReply* pointers and integers (si in your code).
Here is a working example;
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QUrl>
#include <QMap>
#include <QtDebug>
QNetworkAccessManager am;
void finished(QNetworkReply* reply);
QMap<QNetworkReply*, int> requests;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QObject::connect(&am, &QNetworkAccessManager::finished, finished);
QStringList links;
links << "http://google.com";
links << "http://taobao.com";
links << "http://stackoverflow.com";
links << "http://stackexchange.com";
links << "http://bing.com";
for (int i=0; i < links.size(); i++)
{
requests.insert(am.get(QNetworkRequest(QUrl(links[i]))), i);
}
return a.exec();
}
void finished(QNetworkReply* reply)
{
qDebug() << requests[reply];
}
The slot replyFinished(QNetworkReply*) receives pointer to the related reply object. This reply object contains all information about that reply (error code, headers, downloaded data, the URL of the content) and also it contains initial request (QNetworkReply::request()). So, it is possible to check the URL of the request or the URL of actual downloaded content. Note that those URLs may be different.
QNetworkReply::url():
Returns the URL of the content downloaded or uploaded. Note that the
URL may be different from that of the original request.
QNetworkReply::request():
Returns the request that was posted for this reply. In special, note
that the URL for the request may be different than that of the reply.
void MainWindow::replyFinished(QNetworkReply* reply)
{
qDebug() << reply->url();
qDebug() << reply->request().url();
}

Splitting a file into several parts

I'm trying to make a File copying application in Qt. I need to split the source file into several files so that my copy function can copy portions of data one by one and update the QProgressBar. To update the progress accurately I need to split the source file in 1% of its original size. Is my approach wrong. I'm unable to find much resources on this topic.How can I split the source file into several parts of equal size?
The following is a self-contained sketch of such an asynchronous file copier. There are some shortcomings:
The error reporting needs to report QFile error codes as well.
A custom mutex locker class is really needed to deal with mutex RAII.
When looking at the code, ensure that you consider the implementation and the interface (its use) separately. The interface makes it easy to use. The implementation's relative complexity makes the easy to use interface possible.
#include <QApplication>
#include <QByteArray>
#include <QProgressDialog>
#include <QFileDialog>
#include <QBasicTimer>
#include <QElapsedTimer>
#include <QThread>
#include <QMutex>
#include <QFile>
#include <limits>
class FileCopier : public QObject {
Q_OBJECT
QMutex mutable m_mutex;
QByteArray m_buf;
QBasicTimer m_copy, m_progress;
QString m_error;
QFile m_fi, m_fo;
qint64 m_total, m_done;
int m_shift;
void close() {
m_copy.stop();
m_progress.stop();
m_fi.close();
m_fo.close();
m_mutex.unlock();
}
/// Takes the error string from given file and emits an error indication.
/// Closes the files and stops the copy. Always returns false
bool error(QFile & f) {
m_error = f.errorString();
m_error.append(QStringLiteral("(in %1 file").arg(f.objectName()));
emit finished(false, m_error);
close();
return false;
}
void finished() {
emitProgress();
emit finished(m_done == m_total, m_error);
close();
}
void emitProgress() {
emit progressed(m_done, m_total);
emit hasProgressValue(m_done >> m_shift);
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() == m_copy.timerId()) {
// Do the copy
qint64 read = m_fi.read(m_buf.data(), m_buf.size());
if (read == -1) { error(m_fi); return; }
if (read == 0) return finished();
qint64 written = m_fo.write(m_buf.constData(), read);
if (written == -1) { error(m_fo); return; }
Q_ASSERT(written == read);
m_done += read;
}
else if (ev->timerId() == m_progress.timerId())
emitProgress();
}
Q_INVOKABLE void cancelImpl() {
if (!m_fi.isOpen()) return;
m_error = "Canceled";
finished();
}
public:
explicit FileCopier(QObject * parent = 0) :
QObject(parent),
// Copy 64kbytes at a time. On a modern hard drive, we'll copy
// on the order of 1000 such blocks per second.
m_buf(65536, Qt::Uninitialized)
{
m_fi.setObjectName("source");
m_fo.setObjectName("destination");
}
/// Copies a file to another with progress indication.
/// Returns false if the files cannot be opened.
/// This method is thread safe.
Q_SLOT bool copy(const QString & src, const QString & dst) {
bool locked = m_mutex.tryLock();
Q_ASSERT_X(locked, "copy",
"Another copy is already in progress");
m_error.clear();
// Open the files
m_fi.setFileName(src);
m_fo.setFileName(dst);
if (! m_fi.open(QIODevice::ReadOnly)) return error(m_fi);
if (! m_fo.open(QIODevice::WriteOnly)) return error(m_fo);
m_total = m_fi.size();
if (m_total < 0) return error(m_fi);
// File size might not fit into an integer, calculate the number of
// binary digits to shift it right by. Recall that QProgressBar etc.
// all use int, not qint64!
m_shift = 0;
while ((m_total>>m_shift) >= std::numeric_limits<int>::max()) m_shift++;
emit hasProgressMaximum(m_total>>m_shift);
m_done = 0;
m_copy.start(0, this);
m_progress.start(100, this); // Progress is emitted at 10Hz rate
return true;
}
/// This method is thread safe only when a copy is not in progress.
QString lastError() const {
bool locked = m_mutex.tryLock();
Q_ASSERT_X(locked, "lastError",
"A copy is in progress. This method can only be used when"
"a copy is done");
QString error = m_error;
m_mutex.unlock();
return error;
}
/// Cancels a pending copy operation. No-op if no copy is underway.
/// This method is thread safe.
Q_SLOT void cancel() {
QMetaObject::invokeMethod(this, "cancelImpl");
}
/// Signal for progress indication with number of bytes
Q_SIGNAL void progressed(qint64 done, qint64 total);
/// Signals for progress that uses abstract integer values
Q_SIGNAL void hasProgressMaximum(int total);
Q_SIGNAL void hasProgressValue(int done);
///
Q_SIGNAL void finished(bool ok, const QString & error);
};
/// A thread that is always destructible: if quits the event loop and waits
/// for it to finish.
class Thread : public QThread {
public:
~Thread() { quit(); wait(); }
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString src = QFileDialog::getOpenFileName(0, "Source File");
if (src.isEmpty()) return 1;
QString dst = QFileDialog::getSaveFileName(0, "Destination File");
if (dst.isEmpty()) return 1;
QProgressDialog dlg("File Copy Progress", "Cancel", 0, 100);
Q_ASSERT(!dlg.isModal());
Thread thread;
FileCopier copier;
copier.moveToThread(&thread);
thread.start();
dlg.connect(&copier, SIGNAL(hasProgressMaximum(int)),
SLOT(setMaximum(int)));
dlg.connect(&copier, SIGNAL(hasProgressValue(int)),
SLOT(setValue(int)));
copier.connect(&dlg, SIGNAL(canceled()), SLOT(cancel()));
a.connect(&copier, SIGNAL(finished(bool,QString)), SLOT(quit()));
// The copy method is thread safe.
copier.copy(src, dst);
return a.exec();
}
#include "main.moc"
Usually file copying with progress bar is done in this way:
open the source file (for read)
open the destination file (for write)
read a block (64 kB or so) from source file and write it to destination file
update the progress bar
repeat steps 3. and 4. until end of source file
done :) close the files
No need to split file into multiple files. Just process the file by small blocks (block after block), not whole file at once.
The "split file into several files before copying" approach is wrong - this split approach is equally expensive as copying, whole operation would took twice as long and you would need to update progress bar during this splitting too.

C++ API for "Text To speech" and "Voice to Text"

I would like to know whether there is a good API for "voice recognition" and "text to speech" in C++. I have gone through Festival, which you can't even say whether the computer is talking because it is so real and voce as well.
Unfortunately Festival seems not supporting to voice recognition (I mean "Voice to Text") and voce is built in Java and it is a mess in C++ because of JNI.
The API should support both "Text to voice" and "Voice to Text", and it should have a good set of examples, at least outside the owner's website. Perfect if it has a facility to identify set of given voices, but that is optional, so no worries.
What I am going to do with the API is, when set of voice commands given, turn the robot device left, right, etc. And also, speak to me saying "Good Morning", "Good Night" etc. These words will be coded in the program.
Please help me to find a good C++ voice API for this purpose. If you have access to a tutorial/installation tutorial, please be kind enough to share it with me as well.
I found that If I make a audio recording (I used qtmultimedia for this) has to be flac
Read more here
I can then upload to google and then have it send me back some JSON
I then wrote some c++/qt for this to make into a qml plugin
Here is that (alpha) code. Note make sure that you replace
< YOUR FLAC FILE.flac >
with your real flac file.
speechrecognition.cpp
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QSslSocket>
#include <QUrl>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include "speechrecognition.h"
#include <QFile>
#include <QDebug>
const char* SpeechRecognition::kContentType = "audio/x-flac; rate=8000";
const char* SpeechRecognition::kUrl = "http://www.google.com/speech-api/v1/recognize?xjerr=1&client=directions&lang=en";
SpeechRecognition::SpeechRecognition(QObject* parent)
: QObject(parent)
{
network_ = new QNetworkAccessManager(this);
connect(network_, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
}
void SpeechRecognition::start(){
const QUrl url(kUrl);
QNetworkRequest req(url);
req.setHeader(QNetworkRequest::ContentTypeHeader, kContentType);
req.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, false);
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
QNetworkRequest::AlwaysNetwork);
QFile *compressedFile = new QFile("<YOUR FLAC FILE.flac>");
compressedFile->open(QIODevice::ReadOnly);
reply_ = network_->post(req, compressedFile);
}
void SpeechRecognition::replyFinished(QNetworkReply* reply) {
Result result = Result_ErrorNetwork;
Hypotheses hypotheses;
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "ERROR \n" << reply->errorString();
} else {
qDebug() << "Running ParserResponse for \n" << reply << result;
ParseResponse(reply, &result, &hypotheses);
}
emit Finished(result, hypotheses);
reply_->deleteLater();
reply_ = NULL;
}
void SpeechRecognition::ParseResponse(QIODevice* reply, Result* result,
Hypotheses* hypotheses)
{
QString getReplay ;
getReplay = reply->readAll();
qDebug() << "The Replay " << getReplay;
QJsonDocument jsonDoc = QJsonDocument::fromJson(getReplay.toUtf8());
QVariantMap data = jsonDoc.toVariant().toMap();
const int status = data.value("status", Result_ErrorNetwork).toInt();
*result = static_cast<Result>(status);
if (status != Result_Success)
return;
QVariantList list = data.value("hypotheses", QVariantList()).toList();
foreach (const QVariant& variant, list) {
QVariantMap map = variant.toMap();
if (!map.contains("utterance") || !map.contains("confidence"))
continue;
Hypothesis hypothesis;
hypothesis.utterance = map.value("utterance", QString()).toString();
hypothesis.confidence = map.value("confidence", 0.0).toReal();
*hypotheses << hypothesis;
qDebug() << "confidence = " << hypothesis.confidence << "\n Your Results = "<< hypothesis.utterance;
setResults(hypothesis.utterance);
}
}
void SpeechRecognition::setResults(const QString &results)
{
if(m_results == results)
return;
m_results = results;
emit resultsChanged();
}
QString SpeechRecognition::results()const
{
return m_results;
}
speechrecognition.h
#ifndef SPEECHRECOGNITION_H
#define SPEECHRECOGNITION_H
#include <QObject>
#include <QList>
class QIODevice;
class QNetworkAccessManager;
class QNetworkReply;
class SpeechRecognition : public QObject {
Q_OBJECT
Q_PROPERTY(QString results READ results NOTIFY resultsChanged)
public:
SpeechRecognition( QObject* parent = 0);
static const char* kUrl;
static const char* kContentType;
struct Hypothesis {
QString utterance;
qreal confidence;
};
typedef QList<Hypothesis> Hypotheses;
// This enumeration follows the values described here:
// http://www.w3.org/2005/Incubator/htmlspeech/2010/10/google-api-draft.html#speech-input-error
enum Result {
Result_Success = 0,
Result_ErrorAborted,
Result_ErrorAudio,
Result_ErrorNetwork,
Result_NoSpeech,
Result_NoMatch,
Result_BadGrammar
};
Q_INVOKABLE void start();
void Cancel();
QString results()const;
void setResults(const QString &results);
signals:
void Finished(Result result, const Hypotheses& hypotheses);
void resultsChanged();
private slots:
void replyFinished(QNetworkReply* reply);
private:
void ParseResponse(QIODevice* reply, Result* result, Hypotheses* hypotheses);
private:
QNetworkAccessManager* network_;
QNetworkReply* reply_;
QByteArray buffered_raw_data_;
int num_samples_recorded_;
QString m_results;
};
#endif // SPEECHRECOGNITION_H
if you develop on Windows you can use MS Speech API which allow you to perform Voice Recognition (ASR) and Text-to-Speech (TTS).
You can find some examples on this page and a very basic example of Voice Recognition in this post.
You could theoretically use Twilio if you have an internet connection in the robot and are willing to pay for the service. They have libraries and examples for a bunch of different languages and platforms http://www.twilio.com/docs/libraries
Also, check out this blog explaining how to build and control an arduino based robot using Twilio http://www.twilio.com/blog/2012/06/build-a-phone-controlled-robot-using-node-js-arduino-rn-xv-wifly-arduinoand-twilio.html