Subversion Repositories tpanel

Rev

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