Subversion Repositories tpanel

Rev

Rev 477 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
457 andreas 1
/*
2
 * Copyright (C) 2024 by Andreas Theofilu <andreas@theosys.at>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
466 andreas 18
 
459 andreas 19
#include <cstring>
457 andreas 20
 
460 andreas 21
#include <QUdpSocket>
469 andreas 22
#include <QNetworkDatagram>
461 andreas 23
#include <QAudioSink>
24
#include <QAudioSource>
25
#include <QMediaDevices>
471 andreas 26
#include <QMediaRecorder>
27
#include <QAudioInput>
465 andreas 28
#include <QBuffer>
469 andreas 29
#include <QTimer>
466 andreas 30
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
31
#   if QT_VERSION_CHECK(6, 6, 0)
469 andreas 32
#       include <QApplication>
466 andreas 33
#       include <QPermissions>
469 andreas 34
#   endif   // QT_VERSION_CHECK(6, 6, 0)
35
#endif  // defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
465 andreas 36
 
457 andreas 37
#include "tqintercom.h"
474 andreas 38
#include "tresources.h"
461 andreas 39
#include "tconfig.h"
458 andreas 40
#include "terror.h"
457 andreas 41
 
465 andreas 42
#define PACKET_SIZE     172
474 andreas 43
#define DATA_SIZE       160
44
#define HEADER_SIZE     12
459 andreas 45
 
465 andreas 46
using std::string;
459 andreas 47
using std::min;
48
 
460 andreas 49
TQIntercom::TQIntercom(QObject *parent)
50
    : QObject(parent)
457 andreas 51
{
458 andreas 52
    DECL_TRACER("TQIntercom::TQIntercom()");
461 andreas 53
 
54
    mSpkLevel = TConfig::getSystemVolume();
55
    mMicLevel = TConfig::getSystemGain();
470 andreas 56
    mPushTimer = new QTimer();
457 andreas 57
}
58
 
460 andreas 59
TQIntercom::TQIntercom(QObject *parent, INTERCOM_t ic)
60
    : QObject(parent)
458 andreas 61
{
62
    DECL_TRACER("TQIntercom::TQIntercom(INTERCOM_t ic)");
63
 
461 andreas 64
    mSpkLevel = TConfig::getSystemVolume();
65
    mMicLevel = TConfig::getSystemGain();
470 andreas 66
    mPushTimer = new QTimer();
458 andreas 67
    setIntercom(ic);
68
}
69
 
457 andreas 70
TQIntercom::~TQIntercom()
71
{
458 andreas 72
    DECL_TRACER("TQIntercom::~TQIntercom()");
460 andreas 73
 
461 andreas 74
    if (mRemote)
75
        delete mRemote;
76
 
77
    if (mMicrophone)
78
        delete mMicrophone;
79
 
460 andreas 80
    if (mUdpTalker)
461 andreas 81
    {
82
        if (mUdpTalker->isOpen())
83
            mUdpTalker->close();
84
 
460 andreas 85
        delete mUdpTalker;
461 andreas 86
    }
460 andreas 87
 
88
    if (mUdpListener)
461 andreas 89
    {
90
        if (mUdpListener->isOpen())
91
            mUdpListener->close();
92
 
460 andreas 93
        delete mUdpListener;
461 andreas 94
    }
465 andreas 95
 
470 andreas 96
    if (mPushTimer)
469 andreas 97
    {
470 andreas 98
        mPushTimer->stop();
99
        mPushTimer->disconnect();
100
        delete mPushTimer;
469 andreas 101
    }
473 andreas 102
 
103
    if (mPullTimer)
104
    {
105
        mPullTimer->stop();
106
        mPullTimer->disconnect();
107
        delete mPullTimer;
108
    }
457 andreas 109
}
458 andreas 110
 
111
void TQIntercom::setIntercom(INTERCOM_t ic)
112
{
465 andreas 113
    DECL_TRACER("TQIntercom::setIntercom(INTERCOM_t ic)");
114
 
458 andreas 115
    if (ic.ip.empty())
116
    {
117
        MSG_ERROR("No valid IP address!");
118
        return;
119
    }
120
 
459 andreas 121
    if (ic.rxPort < 0 || ic.rxPort > 0x0ffff)
458 andreas 122
    {
123
        MSG_ERROR("Receiver port is invalid! (" << ic.rxPort << ")");
124
        return;
125
    }
126
 
459 andreas 127
    if (ic.txPort < 0 || ic.txPort > 0x0ffff)
458 andreas 128
    {
129
        MSG_ERROR("Transmit port is invalid! (" << ic.txPort << ")");
130
        return;
131
    }
132
 
459 andreas 133
    if (ic.rxPort == 0 && ic.txPort == 0)
134
    {
135
        MSG_ERROR("No transmit and no receive port!");
136
        return;
137
    }
138
 
458 andreas 139
    if (ic.mode < 0 || ic.mode > 2)
140
    {
141
        MSG_ERROR("Invalid mode " << ic.mode << "!");
142
        return;
143
    }
144
 
459 andreas 145
    if (ic.mode == 0 && ic.rxPort == 0)     // listen / receive
146
    {
147
        MSG_ERROR("No network port for listening!");
148
        return;
149
    }
150
 
151
    if (ic.mode == 1 && ic.txPort == 0)     // talk / send
152
    {
153
        MSG_ERROR("No network port for talking!");
154
        return;
155
    }
156
 
458 andreas 157
    mIntercom = ic;
461 andreas 158
    mAudioFormat.setSampleRate(8000);
469 andreas 159
    mAudioFormat.setSampleFormat(QAudioFormat::Int16);
461 andreas 160
    mAudioFormat.setChannelCount(1);
161
    mAudioFormat.setChannelConfig(QAudioFormat::ChannelConfigMono);
162
 
468 andreas 163
    if (mIntercom.mode == 0 || mIntercom.mode == 2)     // talk
465 andreas 164
    {
165
        MSG_DEBUG("Connecting to \"" << mIntercom.ip << "\" on port " << mIntercom.txPort);
468 andreas 166
 
469 andreas 167
        if (TStreamError::checkFilter(HLOG_DEBUG))
168
        {
169
            const QList<QAudioDevice> audioDevices = QMediaDevices::audioInputs();
468 andreas 170
 
469 andreas 171
            for (const QAudioDevice &device : audioDevices)
172
            {
477 andreas 173
                MSG_DEBUG("In ID: " << device.id().toStdString());
174
                MSG_DEBUG("In Description: " << device.description().toStdString());
175
                MSG_DEBUG("In Is default: " << (device.isDefault() ? "Yes" : "No"));
469 andreas 176
            }
468 andreas 177
        }
471 andreas 178
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
179
#   if QT_VERSION_CHECK(6, 6, 0)
180
        QMicrophonePermission microphonePermission;
181
 
182
        switch (qApp->checkPermission(microphonePermission))
183
        {
184
            case Qt::PermissionStatus::Undetermined:
185
                qApp->requestPermission(microphonePermission, this, &TQIntercom::onRecordPermissionGranted);
186
                return;
187
 
188
            case Qt::PermissionStatus::Denied:
189
                qWarning("Microphone permission is not granted!");
190
                return;
191
 
192
            case Qt::PermissionStatus::Granted:
193
                MSG_INFO("Microphone permission is granted.");
194
                break;
195
        }
196
#   endif  // QT_VERSION_CHECK(6, 6, 0)
197
#endif  // defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
465 andreas 198
    }
199
 
468 andreas 200
    if (mIntercom.mode == 1 || mIntercom.mode == 2)     // listen
465 andreas 201
    {
468 andreas 202
        MSG_DEBUG("Receiving on port " << mIntercom.rxPort);
203
 
469 andreas 204
        if (TStreamError::checkFilter(HLOG_DEBUG))
468 andreas 205
        {
469 andreas 206
            const QList<QAudioDevice> audioDevices = QMediaDevices::audioOutputs();
207
 
208
            for (const QAudioDevice &device : audioDevices)
209
            {
477 andreas 210
                MSG_DEBUG("Out ID: " << device.id().toStdString());
211
                MSG_DEBUG("Out Description: " << device.description().toStdString());
212
                MSG_DEBUG("Out Is default: " << (device.isDefault() ? "Yes" : "No"));
471 andreas 213
 
214
                if (device.isDefault())
215
                    mAudioMicDevice = device;
469 andreas 216
            }
468 andreas 217
        }
465 andreas 218
    }
219
 
458 andreas 220
    mInitialized = true;
221
}
222
 
223
void TQIntercom::setSpeakerLevel(int level)
224
{
225
    DECL_TRACER("TQIntercom::setSpeakerLevel(int level)");
226
 
227
    if (level < 0 || level > 100)
228
        return;
229
 
230
    mSpkLevel = level;
470 andreas 231
    qreal volume = QAudio::convertVolume(level, QAudio::LinearVolumeScale, QAudio::LogarithmicVolumeScale);
461 andreas 232
 
233
    if (mIntercom.mode == 0 || mIntercom.mode == 2)
234
    {
235
        if (mRemote)
470 andreas 236
            mRemote->setVolume(volume);
461 andreas 237
    }
458 andreas 238
}
239
 
461 andreas 240
void TQIntercom::setMicrophoneLevel(int level)
458 andreas 241
{
461 andreas 242
    DECL_TRACER("TQIntercom::setMicrophoneLevel(int level)");
458 andreas 243
 
244
    if (level < 0 || level > 100)
245
        return;
246
 
465 andreas 247
    mMicLevel = level;
470 andreas 248
    qreal gain = QAudio::convertVolume(level, QAudio::LinearVolumeScale, QAudio::LogarithmicVolumeScale);
465 andreas 249
 
461 andreas 250
    if (mIntercom.mode == 1 || mIntercom.mode == 2)
251
    {
252
        if (mMicrophone)
470 andreas 253
            mMicrophone->setVolume(gain);
461 andreas 254
    }
458 andreas 255
}
256
 
257
void TQIntercom::start()
258
{
259
    DECL_TRACER("TQIntercom::start()");
260
 
461 andreas 261
    if ((mIntercom.mode == 0 || mIntercom.mode == 2) && mIntercom.rxPort)   // listen
262
    {
473 andreas 263
        if (mPullTimer)
264
            mPullTimer->stop();
265
        else
266
            mPullTimer = new QTimer();
267
 
461 andreas 268
        if (mRemote)
269
            delete mRemote;
270
 
271
        mRemote = new QAudioSink(mAudioFormat, this);
470 andreas 272
        mRemote->setVolume(convertVolume(mSpkLevel));
469 andreas 273
 
274
        if (!spawnServer())
275
            return;
473 andreas 276
 
277
        if (mPullTimer)
278
        {
279
            mPullTimer->disconnect();
280
            QIODevice *io = mRemote->start();
281
 
282
            connect(mPullTimer, &QTimer::timeout, [this, io]()
283
            {
284
                if (!io || !io->isOpen() || mReadBuffer.isEmpty())
285
                    return;
286
 
287
                qint64 len = io->write(mReadBuffer);
288
 
289
                if (len > 0)
290
                    mReadBuffer.remove(0, len);
291
 
292
                MSG_DEBUG("Played " << len << " bytes. " << mReadBuffer.size() << " remaining.");
293
            });
294
 
295
            mPullTimer->start(10);
296
        }
297
 
461 andreas 298
    }
299
 
300
    if ((mIntercom.mode == 1 || mIntercom.mode == 2) && mIntercom.txPort) // talk
301
    {
470 andreas 302
        if (mPushTimer)
303
            mPushTimer->stop();
471 andreas 304
        else
305
            mPushTimer = new QTimer();
470 andreas 306
 
461 andreas 307
        if (mMicrophone)
308
            delete mMicrophone;
309
 
469 andreas 310
        if (mMicDevice)
311
        {
312
            if (mMicDevice->isOpen())
471 andreas 313
                mMicDevice->stop();
469 andreas 314
 
315
            delete mMicDevice;
316
        }
317
 
318
 
471 andreas 319
        mMicrophone = new QAudioSource(mAudioMicDevice, mAudioFormat, this);
320
        connect(mMicrophone, &QAudioSource::stateChanged, this, &TQIntercom::onMicStateChanged);
321
        mMicDevice = new TMicrophone();
322
        mMicDevice->start();
469 andreas 323
 
324
        if (!connectTalker())
325
            return;
470 andreas 326
 
327
        mMicrophone->start(mMicDevice);
328
        QIODevice *io = reinterpret_cast<QIODevice *>(mMicDevice);
329
 
330
        if (mPushTimer)
331
        {
332
            mPushTimer->disconnect();
333
 
334
            connect(mPushTimer, &QTimer::timeout, [this, io]()
335
            {
336
                if (mUdpTalker->state() != QUdpSocket::ConnectedState || io == nullptr)
337
                    return;
338
 
482 andreas 339
                qint64 len = io->bytesAvailable();
471 andreas 340
                MSG_DEBUG(len << " bytes available");
482 andreas 341
                qint64 chunks = len / DATA_SIZE;
470 andreas 342
 
343
                if (chunks > 0)
344
                {
474 andreas 345
                    mMicOpen = true;
346
 
470 andreas 347
                    for (int i = 0; i < chunks; ++i)
348
                    {
474 andreas 349
                        QByteArray buffer(DATA_SIZE, 0);
350
                        QByteArray wbuf(PACKET_SIZE, 0);
351
                        len = io->read(buffer.data(), DATA_SIZE);
470 andreas 352
 
471 andreas 353
                        if (len > 0 && mTalkConnected)
470 andreas 354
                        {
474 andreas 355
                            len = getNextBlock(&wbuf, buffer);
470 andreas 356
                            MSG_DEBUG("Writing bytes: " << len);
474 andreas 357
                            mUdpTalker->write(wbuf.data(), len);
358
                            TError::logHex(wbuf.data(), len);
470 andreas 359
                        }
360
                    }
361
                }
474 andreas 362
                else if (len == 0)
470 andreas 363
                {
474 andreas 364
                    if (!mMicOpen)
365
                    {
477 andreas 366
                        QByteArray buffer(DATA_SIZE, uLawEncodeDigital(0));
474 andreas 367
                        QByteArray wbuf(PACKET_SIZE, 0);
368
                        len = getNextBlock(&wbuf, buffer);
369
                        MSG_DEBUG("Writing bytes: " << len);
370
                        mUdpTalker->write(wbuf.data(), len);
371
                        TError::logHex(wbuf.data(), len);
372
                    }
373
                }
374
                else
375
                {
376
                    mMicOpen = true;
470 andreas 377
                    QByteArray buffer(len, 0);
474 andreas 378
                    QByteArray wbuf(HEADER_SIZE + len, 0);
470 andreas 379
 
471 andreas 380
                    if (mTalkConnected)
381
                    {
474 andreas 382
                        len = getNextBlock(&wbuf, buffer);
471 andreas 383
                        MSG_DEBUG("Writing bytes: " << len);
474 andreas 384
                        mUdpTalker->write(wbuf.data(), len);
471 andreas 385
                    }
470 andreas 386
                }
387
            });
388
 
389
            mPushTimer->start(10);
390
        }
461 andreas 391
    }
458 andreas 392
}
393
 
394
void TQIntercom::stop()
395
{
396
    DECL_TRACER("TQIntercom::stop()");
397
 
461 andreas 398
    if ((mIntercom.mode == 0 || mIntercom.mode == 2) && mIntercom.rxPort)   // listen
399
    {
400
        if (mRemote)
468 andreas 401
        {
473 andreas 402
            if (mPullTimer)
403
            {
404
                mPullTimer->stop();
405
                mPullTimer->disconnect();
406
            }
407
 
461 andreas 408
            mRemote->stop();
468 andreas 409
            delete mRemote;
410
            mRemote = nullptr;
411
        }
412
 
461 andreas 413
        if (mUdpListener)
465 andreas 414
        {
461 andreas 415
            mUdpListener->close();
465 andreas 416
            delete mUdpListener;
417
            mUdpListener = nullptr;
418
        }
461 andreas 419
    }
420
 
421
    if ((mIntercom.mode == 1 || mIntercom.mode == 2) && mIntercom.txPort) // talk
422
    {
470 andreas 423
        if (mPushTimer)
424
        {
425
            mPushTimer->stop();
426
            mPushTimer->disconnect();
427
        }
428
 
429
        if (mMicDevice)
474 andreas 430
        {
470 andreas 431
            mMicDevice->stop();
474 andreas 432
            mMicOpen = false;
433
        }
470 andreas 434
 
461 andreas 435
        if (mMicrophone)
468 andreas 436
        {
461 andreas 437
            mMicrophone->stop();
468 andreas 438
            delete mMicrophone;
439
            mMicrophone = nullptr;
440
        }
461 andreas 441
 
442
        if (mUdpTalker)
468 andreas 443
        {
461 andreas 444
            mUdpTalker->close();
468 andreas 445
            delete mUdpTalker;
446
            mUdpTalker = nullptr;
447
        }
461 andreas 448
    }
458 andreas 449
}
450
 
451
void TQIntercom::setMute(bool mute)
452
{
453
    DECL_TRACER("TQIntercom::setMute(bool mute)");
454
 
461 andreas 455
    if (mIntercom.mode == 1 || mIntercom.mode == 2)
456
    {
457
        if (mMicrophone)
471 andreas 458
            mMicrophone->setVolume(mute ? 0.0 : convertVolume(mMicLevel));
461 andreas 459
    }
458 andreas 460
}
459 andreas 461
 
460 andreas 462
bool TQIntercom::connectTalker()
459 andreas 463
{
460 andreas 464
    DECL_TRACER("TQIntercom::connectTalker()");
459 andreas 465
 
460 andreas 466
    // First we initialize the socket
482 andreas 467
//    QHostAddress hostAddress(QString(mIntercom.ip.c_str()));
459 andreas 468
 
460 andreas 469
    if (mUdpTalker)
461 andreas 470
    {
465 andreas 471
        if (mUdpTalker->isOpen())
472
            mUdpTalker->close();
473
 
460 andreas 474
        delete mUdpTalker;
461 andreas 475
    }
459 andreas 476
 
460 andreas 477
    mUdpTalker = new QUdpSocket(this);
465 andreas 478
    connect(mUdpTalker, &QUdpSocket::stateChanged, this, &TQIntercom::onOutputStateChanged);
479
    connect(mUdpTalker, &QUdpSocket::errorOccurred, this, &TQIntercom::onOutputErrorOccurred);
480
    mUdpTalker->connectToHost(mIntercom.ip.c_str(), mIntercom.txPort);
460 andreas 481
    return true;
459 andreas 482
}
483
 
460 andreas 484
bool TQIntercom::spawnServer()
459 andreas 485
{
460 andreas 486
    DECL_TRACER("TQIntercom::spawnServer()");
459 andreas 487
 
460 andreas 488
    if (mUdpListener)
465 andreas 489
    {
490
        if (mUdpListener->isOpen())
491
            mUdpListener->close();
492
 
460 andreas 493
        delete mUdpListener;
465 andreas 494
    }
459 andreas 495
 
460 andreas 496
    mUdpListener = new QUdpSocket(this);
465 andreas 497
    mUdpListener->setReadBufferSize(PACKET_SIZE);
460 andreas 498
 
499
    if (!mUdpListener->bind(QHostAddress::Any, mIntercom.rxPort))
459 andreas 500
    {
460 andreas 501
        delete mUdpListener;
502
        mUdpListener = nullptr;
465 andreas 503
        MSG_WARNING("Couldn't bind to devices at port " << mIntercom.rxPort << "!");
460 andreas 504
        return false;
459 andreas 505
    }
506
 
465 andreas 507
    connect(mUdpListener, &QUdpSocket::stateChanged, this, &TQIntercom::onInputStateChanged);
508
    connect(mUdpListener, &QUdpSocket::errorOccurred, this, &TQIntercom::onInputErrorOccurred);
509
    connect(mUdpListener, &QUdpSocket::readyRead, this, &TQIntercom::onReadPendingDatagrams);
510
 
460 andreas 511
    return true;
459 andreas 512
}
513
 
470 andreas 514
qreal TQIntercom::convertVolume(int volume)
515
{
516
    DECL_TRACER("TQIntercom::converVolume(int volume)");
517
 
518
    return QAudio::convertVolume(static_cast<qreal>(volume) / qreal(100), QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale);
519
}
520
 
469 andreas 521
void TQIntercom::onRecordPermissionGranted()
522
{
523
    DECL_TRACER("TQIntercom::onRecordPermissionGranted()");
524
 
525
    mRecordPermissionGranted = true;
526
}
527
 
465 andreas 528
void TQIntercom::onReadPendingDatagrams()
459 andreas 529
{
465 andreas 530
    DECL_TRACER("TQIntercom::onReadPendingDatagrams()");
459 andreas 531
 
465 andreas 532
    while (mUdpListener->hasPendingDatagrams())
533
    {
534
        QNetworkDatagram datagram = mUdpListener->receiveDatagram();
535
        QByteArray data = datagram.data();
536
 
469 andreas 537
        if (mRemote)
466 andreas 538
        {
469 andreas 539
            for (qsizetype i = 0; i < data.size(); ++i)
540
            {
474 andreas 541
                if (i < HEADER_SIZE)
542
                    continue;
543
 
477 andreas 544
                uint16_t word = muLawToLinear(data[i]);
469 andreas 545
                uint8_t hbyte = word >> 8;
546
                uint8_t lbyte = word;
547
                mReadBuffer.append(hbyte);
548
                mReadBuffer.append(lbyte);
549
            }
550
 
473 andreas 551
            TError::logHex(data.data(), data.size());
465 andreas 552
        }
553
    }
554
}
555
 
556
void TQIntercom::onInputStateChanged(QAbstractSocket::SocketState socketState)
557
{
558
    DECL_TRACER("TQIntercom::onInputStateChanged(QAbstractSocket::SocketState socketState)");
559
 
460 andreas 560
    if (socketState == QAbstractSocket::ConnectedState)
459 andreas 561
    {
461 andreas 562
        QAudioDevice info(QMediaDevices::defaultAudioInput());
459 andreas 563
 
461 andreas 564
        if (!info.isFormatSupported(mAudioFormat))
565
        {
566
            MSG_WARNING("Raw audio device can not be captured!");
567
            return;
568
        }
465 andreas 569
    }
461 andreas 570
 
465 andreas 571
    stateChangedMessage(socketState, true);
572
}
461 andreas 573
 
465 andreas 574
void TQIntercom::onOutputStateChanged(QAbstractSocket::SocketState socketState)
575
{
576
    DECL_TRACER("TQIntercom::onOutputStateChanged(QAbstractSocket::SocketState socketState)");
577
 
471 andreas 578
    if (socketState == QAbstractSocket::ConnectedState)
579
        mTalkConnected = true;
580
    else
581
        mTalkConnected = false;
582
 
465 andreas 583
    stateChangedMessage(socketState, false);
584
}
585
 
471 andreas 586
void TQIntercom::onMicStateChanged(QAudio::State state)
587
{
588
    DECL_TRACER("TQIntercom::onMicStateChanged(QAudio::State state)");
589
 
590
    switch(state)
591
    {
592
        case QAudio::ActiveState:       MSG_DEBUG("Microphone is active"); break;
593
        case QAudio::SuspendedState:    MSG_DEBUG("Microphone is suspended"); break;
594
        case QAudio::StoppedState:      MSG_DEBUG("Microphone is stopped"); break;
595
        case QAudio::IdleState:         MSG_DEBUG("Microphone is idle"); break;
596
    }
597
}
598
 
465 andreas 599
void TQIntercom::stateChangedMessage(QAbstractSocket::SocketState socketState, bool in)
600
{
601
    if (!TStreamError::checkFilter(HLOG_DEBUG))
602
        return;
603
 
604
    DECL_TRACER("TQIntercom::stateChangedMessage(QAbstractSocket::SocketState socketState, bool in)");
605
 
606
    string dir = in ? "input" : "output";
607
 
608
    if (TStreamError::checkFilter(HLOG_DEBUG))
609
    {
610
        switch(socketState)
611
        {
612
            case QAbstractSocket::UnconnectedState: MSG_DEBUG("State " << dir << ": Unconnected"); break;
613
            case QAbstractSocket::HostLookupState:  MSG_DEBUG("State " << dir << ": Looking up host"); break;
614
            case QAbstractSocket::ConnectingState:  MSG_DEBUG("State " << dir << ": Connecting"); break;
615
            case QAbstractSocket::ConnectedState:   MSG_DEBUG("State " << dir << ": Connected"); break;
616
            case QAbstractSocket::BoundState:       MSG_DEBUG("State " << dir << ": Bound"); break;
617
            case QAbstractSocket::ListeningState:   MSG_DEBUG("State " << dir << ": Listening"); break;
618
            case QAbstractSocket::ClosingState:     MSG_DEBUG("State " << dir << ": Closing"); break;
619
        }
459 andreas 620
    }
621
}
461 andreas 622
 
465 andreas 623
void TQIntercom::onInputErrorOccurred(QAbstractSocket::SocketError socketError)
624
{
625
    DECL_TRACER("TQIntercom::onInputErrorOccurred(QAbstractSocket::SocketError socketError)");
626
 
627
    socketErrorMessages(socketError, "Receive packet");
628
}
629
 
630
void TQIntercom::onOutputErrorOccurred(QAbstractSocket::SocketError socketError)
631
{
632
    DECL_TRACER("TQIntercom::onOutputErrorOccurred(QAbstractSocket::SocketError socketError)");
633
 
634
    socketErrorMessages(socketError, "Send packet");
635
}
636
 
637
void TQIntercom::socketErrorMessages(QAbstractSocket::SocketError socketError, const string& msg)
638
{
639
    DECL_TRACER("TQIntercom::socketErrorMessages(QAbstractSocket::SocketError socketError, const string& msg)");
640
 
641
    switch(socketError)
642
    {
643
        case QAbstractSocket::ConnectionRefusedError:           MSG_ERROR(msg << ": The connection was refused by the peer (or timed out)."); break;
644
        case QAbstractSocket::RemoteHostClosedError:            MSG_ERROR(msg << ": The remote host closed the connection."); break;
645
        case QAbstractSocket::HostNotFoundError:                MSG_ERROR(msg << ": The host address was not found."); break;
646
        case QAbstractSocket::SocketAccessError:                MSG_ERROR(msg << ": The socket operation failed because the application lacked the required privileges."); break;
647
        case QAbstractSocket::SocketResourceError:              MSG_ERROR(msg << ": The local system ran out of resources (e.g., too many sockets)."); break;
648
        case QAbstractSocket::SocketTimeoutError:               MSG_ERROR(msg << ": The socket operation timed out."); break;
649
        case QAbstractSocket::DatagramTooLargeError:            MSG_ERROR(msg << ": The datagram was larger than the operating system's limit."); break;
650
        case QAbstractSocket::NetworkError:                     MSG_ERROR(msg << ": An error occurred with the network (e.g., the network cable was accidentally plugged out)."); break;
651
        case QAbstractSocket::AddressInUseError:                MSG_ERROR(msg << ": The address specified to QAbstractSocket::bind() is already in use and was set to be exclusive."); break;
652
        case QAbstractSocket::SocketAddressNotAvailableError:   MSG_ERROR(msg << ": The address specified to QAbstractSocket::bind() does not belong to the host."); break;
653
        case QAbstractSocket::UnsupportedSocketOperationError:  MSG_ERROR(msg << ": The requested socket operation is not supported by the local operating system (e.g., lack of IPv6 support)."); break;
654
        case QAbstractSocket::ProxyAuthenticationRequiredError: MSG_ERROR(msg << ": The socket is using a proxy, and the proxy requires authentication."); break;
655
        case QAbstractSocket::SslHandshakeFailedError:          MSG_ERROR(msg << ": The SSL/TLS handshake failed, so the connection was closed"); break;
656
        case QAbstractSocket::UnfinishedSocketOperationError:   MSG_ERROR(msg << ": The last operation attempted has not finished yet (still in progress in the background)."); break;
657
        case QAbstractSocket::ProxyConnectionRefusedError:      MSG_ERROR(msg << ": Could not contact the proxy server because the connection to that server was denied"); break;
658
        case QAbstractSocket::ProxyConnectionClosedError:       MSG_ERROR(msg << ": The connection to the proxy server was closed unexpectedly (before the connection to the final peer was established)"); break;
659
        case QAbstractSocket::ProxyConnectionTimeoutError:      MSG_ERROR(msg << ": The connection to the proxy server timed out or the proxy server stopped responding in the authentication phase."); break;
660
        case QAbstractSocket::ProxyNotFoundError:               MSG_ERROR(msg << ": The proxy address set with setProxy() (or the application proxy) was not found."); break;
661
        case QAbstractSocket::ProxyProtocolError:               MSG_ERROR(msg << ": The connection negotiation with the proxy server failed, because the response from the proxy server could not be understood."); break;
662
        case QAbstractSocket::OperationError:                   MSG_ERROR(msg << ": An operation was attempted while the socket was in a state that did not permit it."); break;
663
        case QAbstractSocket::SslInternalError:                 MSG_ERROR(msg << ": The SSL library being used reported an internal error. This is probably the result of a bad installation or misconfiguration of the library."); break;
664
        case QAbstractSocket::SslInvalidUserDataError:          MSG_ERROR(msg << ": Invalid data (certificate, key, cypher, etc.) was provided and its use resulted in an error in the SSL library."); break;
665
        case QAbstractSocket::TemporaryError:                   MSG_ERROR(msg << ": A temporary error occurred (e.g., operation would block and socket is non-blocking)."); break;
666
        case QAbstractSocket::UnknownSocketError:               MSG_ERROR(msg << ": An unidentified error occurred."); break;
667
    }
668
}
466 andreas 669
 
474 andreas 670
long TQIntercom::getNextBlock(QByteArray* target, const QByteArray& data)
671
{
672
    DECL_TRACER("TQIntercom::getNextBlock(QByteArray* target, const QByteArray& data)");
673
 
674
    if (!target)
675
        return 0;
676
 
677
    long size = qMin(data.size(), DATA_SIZE);
678
    mHeader.counter++;
679
    mHeader.position += size;
680
    unsigned char bytes[10];
681
 
682
    if (target)
683
    {
684
        target->clear();
685
 
686
        uint16ToBytes(mHeader.ident, bytes);
687
        target->append(reinterpret_cast<char *>(bytes), 2);
688
        uint16ToBytes(mHeader.counter, bytes);
689
        target->append(reinterpret_cast<char *>(bytes), 2);
690
        uint32ToBytes(mHeader.position, bytes);
691
        target->append(reinterpret_cast<char *>(bytes), 4);
692
        uint16ToBytes(mHeader.unk1, bytes);
693
        target->append(reinterpret_cast<char *>(bytes), 2);
694
        uint16ToBytes(mHeader.unk2, bytes);
695
        target->append(reinterpret_cast<char *>(bytes), 2);
696
        target->append(data.right(size));
697
    }
698
 
699
    return size + HEADER_SIZE;
700
}
701
 
467 andreas 702
/*******************************************************************************
703
 * Methods of class _audioWrite start here
704
 ******************************************************************************/
705
 
470 andreas 706
TMicrophone::TMicrophone()
467 andreas 707
{
469 andreas 708
    DECL_TRACER("TMicrophone::TMicrophone(QAudioSource *source, QObject *parent)");
467 andreas 709
}
710
 
469 andreas 711
TMicrophone::~TMicrophone()
467 andreas 712
{
469 andreas 713
    DECL_TRACER("TMicrophone::~TMicrophone()");
714
}
715
 
470 andreas 716
void TMicrophone::start()
469 andreas 717
{
470 andreas 718
    DECL_TRACER("TMicrophone::start()");
719
 
471 andreas 720
    open(QIODevice::ReadWrite);
721
 
722
    if (!mBuffer.isEmpty())
723
        mBuffer.clear();
469 andreas 724
}
725
 
470 andreas 726
void TMicrophone::stop()
469 andreas 727
{
470 andreas 728
    DECL_TRACER("TMicrophone::stop()");
469 andreas 729
 
470 andreas 730
    mPos = 0;
731
    close();
471 andreas 732
    mBuffer.clear();
469 andreas 733
}
734
 
470 andreas 735
bool _first = true;
736
 
469 andreas 737
qint64 TMicrophone::readData(char* data, qint64 len)
738
{
470 andreas 739
//    DECL_TRACER("TMicrophone::readData(char* data, qint64 len)");
469 andreas 740
 
467 andreas 741
    qint64 total = 0;
742
 
743
    if (!mBuffer.isEmpty())
744
    {
469 andreas 745
        qint64 posBuffer = 0;
746
        qint64 posData = 0;
747
        qint64 size = qMin(len, mBuffer.size());
474 andreas 748
        qint16 hbyte, lbyte, word;
749
        bool bigEndian = isBigEndian();
469 andreas 750
 
751
        while (posData < size)
467 andreas 752
        {
470 andreas 753
            if (posBuffer >= mBuffer.size())
754
                break;
755
 
474 andreas 756
            hbyte = mBuffer[posBuffer];
469 andreas 757
            posBuffer++;
474 andreas 758
            lbyte = mBuffer[posBuffer];
469 andreas 759
            posBuffer++;
474 andreas 760
 
761
            if (bigEndian)
762
                word = ((hbyte << 8) & 0xff00) | lbyte;
763
            else
764
                word = ((lbyte << 8) & 0xff00) | hbyte;
765
 
477 andreas 766
            *(data+posData) = linearToMuLaw(word);
469 andreas 767
            posData++;
467 andreas 768
        }
769
 
470 andreas 770
        mBuffer.remove(0, posBuffer);
469 andreas 771
        total = posData;
467 andreas 772
    }
773
 
774
    return total;
775
}
776
 
469 andreas 777
qint64 TMicrophone::writeData(const char* data, qint64 len)
467 andreas 778
{
469 andreas 779
    DECL_TRACER("TMicrophone::writeData(const char* data, qint64 len)");
467 andreas 780
 
470 andreas 781
    if (len > 0)
782
        mBuffer.append(data, len);
783
 
471 andreas 784
    MSG_DEBUG("Wrote " << len << " bytes to buffer.");
470 andreas 785
    return len;
467 andreas 786
}
787
 
470 andreas 788
qint64 TMicrophone::bytesAvailable() const
789
{
790
//    DECL_TRACER("TMicrophone::bytesAvailable() const");
791
 
792
    return (mBuffer.size() / 2) + QIODevice::bytesAvailable();
793
}