summaryrefslogtreecommitdiffstats
path: root/app/main.cpp
blob: 8fa8117e7cd005a0c2db07d27ca3804264b9acba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
 * Copyright (C) 2016 The Qt Company Ltd.
 * Copyright (C) 2017 Konsulko Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <QtCore/QCommandLineParser>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QStandardPaths>
#include <QtCore/QUrlQuery>
#include <QtGui/QGuiApplication>
#include <QtQml/QQmlApplicationEngine>
#include <QtQml/QQmlContext>
#include <QtQml/qqml.h>
#include <QtQuickControls2/QQuickStyle>
#include <QQuickWindow>
#include <libhomescreen.hpp>
#include <qlibwindowmanager.h>
#include <bluetooth.h>
#include <mediaplayer.h>

int main(int argc, char *argv[])
{
    QString myname = QString("MediaPlayer");

    QGuiApplication app(argc, argv);

    QQuickStyle::setStyle("AGL");

    QQmlApplicationEngine engine;
    QQmlContext *context = engine.rootContext();

    QCommandLineParser parser;
    parser.addPositionalArgument("port", app.translate("main", "port for binding"));
    parser.addPositionalArgument("secret", app.translate("main", "secret for binding"));
    parser.addHelpOption();
    parser.addVersionOption();
    parser.process(app);
    QStringList positionalArguments = parser.positionalArguments();

    if (positionalArguments.length() == 2) {
        int port = positionalArguments.takeFirst().toInt();
        QString secret = positionalArguments.takeFirst();
        QUrl bindingAddress;
        bindingAddress.setScheme(QStringLiteral("ws"));
        bindingAddress.setHost(QStringLiteral("localhost"));
        bindingAddress.setPort(port);
        bindingAddress.setPath(QStringLiteral("/api"));
        QUrlQuery query;
        query.addQueryItem(QStringLiteral("token"), secret);
        bindingAddress.setQuery(query);
        context->setContextProperty(QStringLiteral("bindingAddress"), bindingAddress);
        std::string token = secret.toStdString();
        LibHomeScreen* hs = new LibHomeScreen();
        QLibWindowmanager* qwm = new QLibWindowmanager();

        // WindowManager
        if(qwm->init(port,secret) != 0){
            exit(EXIT_FAILURE);
        }
        // Request a surface as described in layers.json windowmanager’s file
        if (qwm->requestSurface(myname) != 0) {
            exit(EXIT_FAILURE);
        }
        // Create an event callback against an event type. Here a lambda is called when SyncDraw event occurs
        qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw, [qwm, myname](json_object *object) {
            fprintf(stderr, "Surface got syncDraw!\n");
            qwm->endDraw(myname);
        });

        // HomeScreen
        hs->init(port, token.c_str());
        // Set the event handler for Event_TapShortcut which will activate the surface for windowmanager
        hs->set_event_handler(LibHomeScreen::Event_TapShortcut, [qwm, myname](json_object *object){
            json_object *appnameJ = nullptr;
            if(json_object_object_get_ex(object, "application_name", &appnameJ))
            {
                const char *appname = json_object_get_string(appnameJ);
                if(myname == appname)
                {
                    qDebug("Surface %s got tapShortcut\n", appname);
                    qwm->activateSurface(myname);
                }
            }
        });

        context->setContextProperty("mediaplayer", new Mediaplayer(bindingAddress));
        context->setContextProperty("bluetooth_connection", new Bluetooth(bindingAddress));
        engine.load(QUrl(QStringLiteral("qrc:/MediaPlayer.qml")));
        QObject *root = engine.rootObjects().first();
        QQuickWindow *window = qobject_cast<QQuickWindow *>(root);
        QObject::connect(window, SIGNAL(frameSwapped()), qwm, SLOT(slotActivateSurface()
        ));
    }
    return app.exec();
}
rovides function style API calling interface. So you should include libsoundmanager.hpp headerfile, and should link this library. Please also refer sample application and template. See also our [Sample code](#Sample\ code). <br /> * * * ## **<div id="Supported\ usecase">Supported usecase</div>** 1. Active source change - When user choose different audio source with current one, IVI system stop or pause current source and activate new one. - When user connect external device e.g. iPhone, USB memory IVI system change active source automatically to connected one. 2. Active source locking - When user is in phone call, IVI restrict to change active source. 3. Interrupt source mixing - When car close to cross road IVI system reduce the volume of current source and mix with interrupt source e.g. Navigation Guidance. 4. Volume change - User can change the volume of active source or sink. - When user change volume during interruption e.g. Navigation Guidance, IVI system change its volume temporary or permanently. 5. Mute/unmute - User can mute/unmute current active source. 6. Volume management - When user change active source, IVI system mute/unmute to avoid distortion of sound. 7. Volume acceleration - When road noise is increased by speed, IVI system automatically change the volume of active source. 8. Routing sound - System needs to route sound stream to proper zones. (driver zone, passenger zone, rear seat zone) [See also this page](https://wiki.automotivelinux.org/eg-ui-graphics-req-audiorouting) * * * ## **<div id="Software\ Architecture">Software Architecture</div>** The architecture of Sound Manager is shown below. Sound Manager is the service designed to be used by multiple applications. Therefore Sound Manager framework consists on two binder layers. Please refer the following figure. The upper binder is for application side security context for applications. The lower binder is for servide side security context. Usually application side binder has some business logic for each application, so the number of binders depend on the number of applications which use Sound Manager. On the other hand, regarding lower binder there is only one module in the system. This binder receives all messages from multiple applications (in detail, it comes from upper layer binder). The communication protocols between libsoundmanager and upper binder, upper binder and lower binder, lower binder (soundmanager-binding) and AudioManager are WebSocket. ![software-stack.png](parts/software-stack.png) * * * ## **<div id="API\ reference">API reference</div>** "libsoundmanager" and "soundmanager_binding" provides several kinds of APIs, and these APIs basically correspond to GENIVI Audio Manager API. (Some APIs are Sound Manager original functions.) For understanding, GENIVI Audio Manager stands for one core module and three plug-ins. 1. AudioManagerDaemon This is a core module of Audio Manager. 2. AudioManagerCommandPlugin This is a command interface for Audio Manager. 3. AudioManagerController This plug-in can be used for sound-right management. 4. AudioManagerRountingPlugin This plug-in abstracts the hardware and software. And sometimes there may be multiple plug-ins. *) [See also GENIVI AudioManager Components](http://docs.projects.genivi.org/AudioManager/audiomanagercomponentspage.html) ![See also GENIVI AudioManager Components](parts/am-component.png) (This figure was copied from GENIVI Web page.) ### **<div id="APIs">APIs</div>** - [init(int port, const std::string& token)]() - [registerSource(const std::string& sourceName)](http://docs.projects.genivi.org/AudioManager/a00053.html#acadce23459d94cec496d17700cbde230) - [connect(int sourceID, int sinkID)](http://docs.projects.genivi.org/AudioManager/a00033.html#a62d8f5aee1e601d59f993c5a5561e234) - [connect(int sourceID, const std::string& sinkName = "default")](http://docs.projects.genivi.org/AudioManager/a00033.html#a62d8f5aee1e601d59f993c5a5561e234) - [disconnect(int connectionID)](http://docs.projects.genivi.org/AudioManager/a00033.html#aa24d0146f4e3c75e02d6c0152e246da1) - [ackSetSourceState(int sourceID, int handle, int errno)](http://docs.projects.genivi.org/AudioManager/a00053.html#a11f6b0378a50296a72107d6a1fa7ec21) - [LibSoundmanager ()](api-ref/html/class_lib_soundmanager.html#a8b51e9891813cb62dd12109c017ad106) - [set_event_handler(enum EventType_AsyncSetSourceState et, handler_asyncSetSourceState f)]() - [register_callback( void (*event_cb)(const std::string& event, struct json_object* event_contents), void (*reply_cb)(struct json_object* reply_contents), void (*hangup_cb)(void) = nullptr)]() - [register_callback( void (*reply_cb)(struct json_object* reply_contents), void (*hangup_cb)(void) = nullptr)]() The below APIs will be available at RC2. - [setVolume (const am_sinkID_t sinkID, const am_mainVolume_t volume)](http://docs.projects.genivi.org/AudioManager/a00033.html#a6d47bc67473d75495260abe8c666fc7e) - [volumeStep (const am_sinkID_t sinkID, const int16_t volumeStep)](http://docs.projects.genivi.org/AudioManager/a00033.html#ad7a4c1fe5a2ecfaae5484a14d8820e58) - [setSinkMuteState (const am_sinkID_t sinkID, const am_MuteState_e muteState)](http://docs.projects.genivi.org/AudioManager/a00033.html#afae22041843c5349be16a6593d3ebb9c) - [getListMainConnections (std::vector< am_MainConnectionType_s > &listConnections)](http://docs.projects.genivi.org/AudioManager/a00033.html#a59d10a7178e3227d0b8f415308c71179) - [confirmRoutingReady (const uint16_t handle, const am_Error_e error)](http://docs.projects.genivi.org/AudioManager/a00053.html#a1dd1b89cccffeaafb1a3c11cebd7e48c) ### **<div id="Events">Events</div>** - [EventType_AsyncSetSourceState]() The below Events will be available at RC2. - [EventType_NewMainConnection](http://docs.projects.genivi.org/AudioManager/a00034.html#a69ada9e19c65c1d078d8a5f473d08586) - [EventType_RemovedMainConnection](http://docs.projects.genivi.org/AudioManager/a00034.html#aa3b5906bcf682cff155fb24d402efd89) - [EventType_MainConnectionStateChanged](http://docs.projects.genivi.org/AudioManager/a00034.html#a32aa8ab84632805a876e023a7aead810) - [EventType_VolumeChanged](http://docs.projects.genivi.org/AudioManager/a00034.html#a4494fdd835137e572f2cf4a3aceb6ae5) - [EventType_SinkMuteStateChanged](http://docs.projects.genivi.org/AudioManager/a00034.html#a6068ce59089fbdc63aec81e778aba238) - [EventType_setRoutingReady](http://docs.projects.genivi.org/AudioManager/a00054.html#a7a4d410e30df0e8240d25a57e3c72c6b) - [EventType_asyncConnect](http://docs.projects.genivi.org/AudioManager/a00054.html#a8a81297be9c64511e27d85444c59b0d6) - [EventType_asyncSetSourceState](http://docs.projects.genivi.org/AudioManager/a00054.html#ab02d93d54ee9cd98776a3f2d274ee24d) - [EventType_asyncDisconnect](http://docs.projects.genivi.org/AudioManager/a00054.html#a93ae95515730eb615ab5dfc1316d7862) * * * ## **<div id="Sequence">Sequence</div>** ### **<div id="StartUp">StartUp</div>** ![seq_startup.png](parts/seq_startup.svg) ### **<div id="Registration">Registration</div>** ![seq_registration.png](parts/seq_registration.svg) ### **<div id="Request\ Sound\ Right">Request Sound Right</div>** ![seq_requestsoundmode.png](parts/seq_requestsoundmode.svg) ### **<div id="Connect\ Sound\ Route">Connect Sound Route</div>** ![seq_connectsoundroute.png](parts/seq_connectsoundroute.svg) ### **<div id="Start\ Sound\ Streaming">Start Sound Streaming</div>** ![seq_startsoundstreaming.png](parts/seq_startsoundstreaming.svg) ### **<div id="Stop\ Sound\ Streaming">Stop Sound Streaming</div>** ![seq_stopsoundstreaming.png](parts/seq_stopsoundstreaming.svg) ### **<div id="Disconnect\ Sound\ Route">Disconnect Sound Route</div>** ![seq_disconnectsoundroute.png](parts/seq_disconnectsoundroute.svg) ### **<div id="Change\ Volume">Change Volume</div>** ![seq_changevolume.png](parts/seq_changevolume.svg) ### **<div id="Set\ Mute\ State">Set Mute State</div>** ![seq_setmutestate.png](parts/seq_setmutestate.svg) ### **<div id="Release\ Sound\ Right">Release Sound Right</div>** ![seq_releasesoundmode.png](parts/seq_releasesoundmode.svg) * * * ### **<div id="Audio\ Domain">Audio Domain</div>** One of the most important concept of Audio Manager is Audio Domain. To use GENIVI Audio Manager based system, it may be better to understand this concept. The below document should bring good understanding. [GENIVI Audio Manager: Generic Controller Plug-in](http://events.linuxfoundation.org/sites/events/files/slides/AGL_AMM_presentation_A01.pdf) Although strongly recommended to read whole pages, but you can get quick understanding by page.10 to 14. # **<div id="Sample\ code">Sample code</div>** You can find sample implementation of Sound Manager as below. * `apps/agl-service-homescreen-2017/sample/template` * `apps/agl-service-homescreen-2017/sample/radio` * `apps/agl-service-homescreen-2017/sample/mediaplayer` # **<div id="Limitation">Limitation</div>** * Minimum APIs and Events are prepared for RC1, the following APIs will be available for RC2. * setVolume * volumeStep * setSinkMuteState * getListMainConnections * confirmRoutingReady * EventType_NewMainConnection * EventType_RemovedMainConnection * EventType_MainConnectionStateChanged * EventType_VolumeChanged * EventType_SinkMuteStateChanged * EventType_setRoutingReady * EventType_asyncConnect * EventType_asyncSetSourceState * EventType_asyncDisconnect