/* SPDXLicenseID: MPL-2.0 * * Copyright (C) 2014, GENIVI Alliance * * This file is part of AudioManager Monitor * * This Source Code Form is subject to the terms of the Mozilla Public * License (MPL), v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * For further information see http://www.genivi.org/. * * List of changes: */ import QtQuick 2.1 import QtQuick.Window 2.0 import com.windriver.ammonitor 1.0 import "code.js" as Code Item { id: mainBox PAClient { id: paClient signal sinkInputProcessed(int processType, int index) signal sinkInfoProcessed(int processType, int index) onSinkInputChanged : { if (sinkinput.role && sinkinput.role != "event" && sinkinput.role != "filter") { console.log('onSinkInputChanged '+sinkinput.index+' Volume'+sinkinput.volume); Code.savePASinkInput(sinkinput); architectureDiagram.requestPaint(); pulseaudioChart.updateData(sinkinput.role, sinkinput.index, sinkinput.volume); console.log('----'); for (var prop in sinkinput) console.log("Object item:", prop, "=", sinkinput[prop]) console.log('----'); sinkInputProcessed(0, sinkinput.index); } } onSinkInputRemoved : { console.log('onSinkInputRemoved '+index); var sinkinput = Code.takePASinkInput(index); if (sinkinput && sinkinput.role != "event") { console.log('----'); for (var prop in sinkinput) console.log("Object item:", prop, "=", sinkinput[prop]) console.log('----'); pulseaudioChart.removeData(sinkinput.role, sinkinput.index); } sinkInputProcessed(1, index); architectureDiagram.requestPaint(); } onSinkInfoChanged: { console.log("onSinkInfoChanged " + sinkinfo.index + " Volume " + sinkinfo.volume); Code.savePASinkInfo(sinkinfo); architectureDiagram.requestPaint(); audiomanagerChart.updateData(sinkinfo.name, sinkinfo.index, sinkinfo.volume); sinkInfoProcessed(0, sinkinfo.index); } onSinkInfoRemoved: { console.log("onSinkInfoRemoved " + index); var sinkinfo = Code.takePASinkInfo(index); audiomanagerChart.removeData(sinkinfo.name, sinkinfo.index); architectureDiagram.requestPaint(); } onClientChanged: { console.log("onClientChanged " + client.index + " name " + client.name); Code.savePAClient(client); architectureDiagram.requestPaint(); } onClientRemoved: { console.log("onClientRemoved " + index); var client = Code.takePAClient(index); architectureDiagram.requestPaint(); } } AMClient { id: amClient property bool initialized: false onSinkAdded: { // skip default AM Sinks if(sink.name.substr(0, 2) == "my") return; if(!initialized) { Code.amSinks[Code.amSinks.length] = sink console.log("SINK ADDED : " + sink.id + " / " + sink.name); } } onSinkRemoved: { } onVolumeChanged: { console.log("**********************************"); console.log("QML : VOLUME CHANGED : SINKID = " + sinkid + " / VOLUME = " + volume); console.log("**********************************"); } onSourceAdded: { // skip default AM Sources if(source.name.substr(0, 2) == "my") return; if(!initialized) { Code.amSources[Code.amSources.length] = source console.log("SOURCE ADDED : " + source.id + " / " + source.name); } } onSourceRemoved: { } onConnectionAdded: { console.log("**********************************"); console.log("QML : CONNECTION : " + connection.id+ " "+initialized); console.log("**********************************"); if(!initialized) { // remove previous connection amClient.disconnect(connection.id); return; } Code.saveAMConnection(connection); } onConnectionRemoved: { console.log("**********************************"); console.log("QML : CONNECTION REMOVED : " + index); console.log("**********************************"); var conn = Code.takeAMConnection(index); } onInitAMMonitorCompleted: { console.log("onInitDBusCallCompleted"); amClient.initialized = true; } } Rectangle { id: buttonPanel color: "transparent" anchors.left: parent.left anchors.top: parent.top anchors.topMargin: parent.height / 40 width: parent.width / 6 height: parent.height property int buttonWidth : width * 9 / 10 property int buttonHeight : height / 7 ListView { id: buttonsView anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter anchors.fill: parent orientation: ListView.Vertical model: VisualItemModel { Text { text: "Audio Players of IVI" font.pixelSize: parent.height / 30 anchors.horizontalCenter: parent.horizontalCenter } Button { width: buttonPanel.buttonWidth height: buttonPanel.buttonHeight iconName: "music" title: "Media" amCommandIF: amClient amSource: "MediaPlayer" amSink: "AlsaPrimary" mediaRole: "MEDIA" audioFilePath: "audio/media.wav" } Button { width: buttonPanel.buttonWidth height: buttonPanel.buttonHeight iconName: "car" title: "Navi" amCommandIF: amClient amSource: "NaviPlayer" amSink: "AlsaSecondary" mediaRole: "NAVI" audioFilePath: "audio/navigation.wav" } Button { width: buttonPanel.buttonWidth height: buttonPanel.buttonHeight iconName: "phone" title: "Phone" amCommandIF: amClient amSource: "Skype" amSink: "AlsaSecondary" mediaRole: "skype" audioFilePath: "audio/telephone-ring.wav" } Button { width: buttonPanel.buttonWidth height: buttonPanel.buttonHeight iconName: "microphone" title: "TTS" amCommandIF: amClient amSource: "TTSPlayer" amSink: "AlsaSecondary" mediaRole: "TextToSpeach" audioFilePath: "audio/tts.wav" } Button { width: buttonPanel.buttonWidth height: buttonPanel.buttonHeight iconName: "reply" title: "Reverse" amCommandIF: amClient amSource: "ReverseBeep" amSink: "AlsaSecondary" mediaRole: "reverse" audioFilePath: "audio/car_reverse.wav" } Text { text: "(Press audio play button to\nconnect the AM source and sink)" font.pixelSize: buttonPanel.height / 60 anchors.horizontalCenter: parent.horizontalCenter height: 50 } } } } Rectangle { id: amVolumeChartPanel anchors.left: buttonPanel.right anchors.top: parent.top width: parent.width * 2 / 6 height: parent.height / 2 /* Text { text: "50" font.pixelSize: parent.height / 20 anchors.right: audiomanagerChart.left anchors.verticalCenter: parent.verticalCenter anchors.rightMargin: 5 } */ Graph { id: audiomanagerChart graphName : "AudiomanagerChart" title: "Sinks of GENIVIĀ® Audio Manager" description: "AM's Sink volume changes by Control Plugin" anchors.fill: parent defaultValue : 0 maxDataLength: 100 width: parent.width height: parent.height type: Code.GraphType.CONTINUOUS_LINE } } Rectangle { id: pulseaudioVolumeChartPanel anchors.left: buttonPanel.right anchors.top: amVolumeChartPanel.bottom width: parent.width * 2 / 6 height: parent.height / 2 Graph { id: pulseaudioChart title: "Sink Inputs of PulseAudio" description: "PA's Sink Input volume changes" anchors.fill: parent graphName : "PulseAudioChart" defaultValue : 0 maxDataLength: 100 width: parent.width height: parent.height type: Code.GraphType.TRANSIENT_LINE } } Rectangle { id: dialogPanel anchors.left: amVolumeChartPanel.right anchors.top: parent.top width: parent.width * 3 / 6 height: parent.height Canvas { id: architectureDiagram anchors.fill: parent property string geniviLogo:"images/genivi-logo.png" property string pulseaudioLogo:"images/pulseaudio-logo.png" property string speaker:"images/speaker.png" Component.onCompleted: { loadImage(geniviLogo); loadImage(pulseaudioLogo); loadImage(speaker); } function plugInSocket(x, y, name, length, rotate) { var ctx = getContext('2d'); var r = 5; var w = 16; var h = 16; ctx.save(); // adjust position if(rotate == 90) { ctx.translate(x+w, y-h/2) ctx.rotate(Math.PI/2) } else if(rotate == 180) { ctx.translate(x-w/2, y-h) } else { // 0 ctx.translate(x+w/2, y+h) ctx.rotate(Math.PI) // default degree } length -= h ctx.strokeStyle = "#222222" ctx.lineWidth = 1.0 ctx.fillStyle = "#0099ff" ctx.font = "12px sans-serif" ctx.beginPath(); // top ctx.lineTo(w-r,0); // draw top right corner ctx.arcTo(w,0,w,r,r); ctx.lineTo(w,h); // right side ctx.lineTo(0,h); // bottom side ctx.lineTo(0,r); // left side // draw top left corner ctx.arcTo(0,0,r,0,r); ctx.closePath(); ctx.fill(); ctx.stroke(); // plug ctx.fillStyle = "white" var plugW = 4 var plugH = 7 ctx.beginPath(); ctx.lineTo(w/3 - plugW/2, h); ctx.lineTo(w/3 - plugW/2, h+plugH); ctx.lineTo(w/3 + plugW/2, h+plugH); ctx.lineTo(w/3 + plugW/2, h); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.beginPath(); ctx.lineTo(w*2/3 - plugW/2, h); ctx.lineTo(w*2/3 - plugW/2, h+plugH); ctx.lineTo(w*2/3 + plugW/2, h+plugH); ctx.lineTo(w*2/3 + plugW/2, h); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.beginPath(); ctx.lineTo(w/2 - plugW/2, 0); ctx.lineTo(w/2 - plugW/2, - length); ctx.lineTo(w/2 + plugW/2, - length); ctx.lineTo(w/2 + plugW/2, 0); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.restore(); ctx.save() ctx.translate(x, y) ctx.rotate(0) ctx.fillStyle = "black"; var m = ctx.measureText(name); var tx = (w - m.width)/2, ty = length if(rotate == 90) tx = (w - m.width)/2, ty = length/3 else if(rotate == 180) tx = (w - m.width)/2, ty = - length/3 ctx.fillText(name, tx, ty) ctx.restore(); } function roundRect(x, y, w, h, name, verticalCenter,initCB,postCB) { var ctx = getContext('2d'); var r = 10; ctx.save(); ctx.translate(x, y) var fontSize = 12; ctx.font = ""+fontSize+"px sans-serif" if(initCB != null) initCB(ctx); else { ctx.strokeStyle = "#222222" ctx.lineWidth = 1.0 ctx.fillStyle = "lightGray" } ctx.beginPath(); // top ctx.lineTo(w-r,0); // draw top right corner ctx.arcTo(w,0,w,r,r); ctx.lineTo(w,h-r); // right side // draw bottom right corner ctx.arcTo(w,h,w-r,h,r); ctx.lineTo(r,h); // bottom side // draw bottom left corner ctx.arcTo(0,h,0,h-r,r); ctx.lineTo(0,r); // left side // draw top left corner ctx.arcTo(0,0,r,0,r); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.fillStyle = "black"; var m = ctx.measureText(name); if(verticalCenter) ctx.fillText(name, (w - m.width)/2, (h+fontSize)/2); else ctx.fillText(name, (w - m.width)/2, 16); if(postCB != null) postCB(ctx); ctx.restore(); } function audioManager() { this.w=parent.width*2/3, this.h=parent.height*2/5 this.x = (parent.width - this.w)/2 - this.w/10, this.y = parent.height/6 var logoWidth = this.h/2 var logoHeight = this.h/2 var logoX = (this.w - logoWidth)/2 var logoY = (this.h - logoHeight)/2 roundRect(this.x, this.y, this.w, this.h, "GENIVIĀ® Audio Manager", false, null, function(ctx) { ctx.drawImage(geniviLogo, logoX, logoY, logoWidth, logoHeight); }); // AM Sources var ctx = getContext('2d'); var bx = this.x + this.w/16; var by = this.y+this.h/10; var tw = this.w/4 var th = this.h/8 var sourceJCX = bx+tw var sourceJCY = by+10 ctx.fillText(Code.amSources.length+" AM Source(s)", bx, by) for(var i=0; i