summaryrefslogtreecommitdiffstats
path: root/app/images/HMI_Phone_Button_3_Active-01.svg
blob: d5524d90f059c89c3ebd45a115009d605a17c6ae (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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->

<svg
   xmlns:i="&amp;#38;ns_ai;"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   version="1.1"
   x="0px"
   y="0px"
   viewBox="0 0 172 172"
   style="enable-background:new 0 0 172 172;"
   xml:space="preserve"
   id="svg2"
   inkscape:version="0.91 r13725"
   sodipodi:docname="HMI_Phone_Button_3_Active-01.svg"><metadata
     id="metadata94"><rdf:RDF><cc:Work
         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
     id="defs92" /><sodipodi:namedview
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1"
     objecttolerance="10"
     gridtolerance="10"
     guidetolerance="10"
     inkscape:pageopacity="0"
     inkscape:pageshadow="2"
     inkscape:window-width="2560"
     inkscape:window-height="1464"
     id="namedview90"
     showgrid="false"
     inkscape:zoom="1.372093"
     inkscape:cx="-591.06779"
     inkscape:cy="85.999999"
     inkscape:window-x="0"
     inkscape:window-y="0"
     inkscape:window-maximized="1"
     inkscape:current-layer="svg2" /><style
     type="text/css"
     id="style4">
	.st0{display:none;}
	.st1{display:inline;}
	.st2{opacity:0.15;fill:url(#SVGID_1_);}
	.st3{opacity:0.15;fill:url(#SVGID_2_);stroke:url(#SVGID_3_);stroke-miterlimit:10;}
	.st4{fill:url(#SVGID_4_);}
	.st5{display:inline;fill:#66FF99;}
	.st6{font-family:'Roboto-Light';}
	.st7{font-size:78.8169px;}
	.st8{opacity:0.15;fill:url(#SVGID_5_);}
	.st9{opacity:0.35;fill:url(#SVGID_6_);}
	.st10{opacity:0.15;fill:url(#SVGID_7_);}
	.st11{opacity:0.15;fill:url(#SVGID_8_);stroke:url(#SVGID_9_);stroke-miterlimit:10;}
	.st12{fill:url(#SVGID_10_);}
	.st13{fill:#FFFFFF;}
</style><switch
     id="switch6"><g
       i:extraneous="self"
       id="g8"><g
         id="Active"><linearGradient
           id="SVGID_5_"
           gradientUnits="userSpaceOnUse"
           x1="1.2348"
           y1="170.7652"
           x2="170.7652"
           y2="1.2348"><stop
             offset="0"
             style="stop-color:#FFFFFF;stop-opacity:0"
             id="stop45" /><stop
             offset="1"
             style="stop-color:#000000"
             id="stop47" /></linearGradient><rect
           x="1.2"
           y="1.2"
           class="st8"
           width="169.5"
           height="169.5"
           id="rect49" /><linearGradient
           id="SVGID_6_"
           gradientUnits="userSpaceOnUse"
           x1="-0.9569"
           y1="168.4538"
           x2="172.9569"
           y2="3.5462"><stop
             offset="0.136"
             style="stop-color:#5DFE9F;stop-opacity:0.94"
             id="stop52" /><stop
             offset="0.6043"
             style="stop-color:#6BFBFF;stop-opacity:0.6"
             id="stop54" /></linearGradient><rect
           x="1.2"
           y="1.2"
           class="st9"
           width="169.5"
           height="169.5"
           id="rect56" /><g
           id="g58"><linearGradient
             id="SVGID_7_"
             gradientUnits="userSpaceOnUse"
             x1="1.2348"
             y1="170.7652"
             x2="170.7652"
             y2="1.2348"><stop
               offset="0"
               style="stop-color:#FFFFFF;stop-opacity:0"
               id="stop61" /><stop
               offset="1"
               style="stop-color:#000000"
               id="stop63" /></linearGradient><rect
             x="1.2"
             y="1.2"
             class="st10"
             width="169.5"
             height="169.5"
             id="rect65" /><linearGradient
             id="SVGID_8_"
             gradientUnits="userSpaceOnUse"
             x1="1"
             y1="171"
             x2="171"
             y2="1"><stop
               offset="0"
               style="stop-color:#FFFFFF;stop-opacity:0"
               id="stop68" /><stop
               offset="1"
               style="stop-color:#000000"
               id="stop70" /></linearGradient><linearGradient
             id="SVGID_9_"
             gradientUnits="userSpaceOnUse"
             x1="-1.7107"
             y1="169.1686"
             x2="173.7107"
             y2="2.8314"><stop
               offset="0"
               style="stop-color:#8BC53F"
               id="stop73" /><stop
               offset="1"
               style="stop-color:#0DF9FF"
               id="stop75" /></linearGradient><rect
             x="1"
             y="1"
             class="st11"
             width="170"
             height="170"
             id="rect77" /><g
             id="g79"><linearGradient
               id="SVGID_10_"
               gradientUnits="userSpaceOnUse"
               x1="-2.2236"
               y1="169.6549"
               x2="174.2236"
               y2="2.3451"><stop
                 offset="0"
                 style="stop-color:#59FF7F"
                 id="stop82" /><stop
                 offset="1"
                 style="stop-color:#6BFBFF"
                 id="stop84" /></linearGradient><path
               class="st12"
               d="M171,1v170H1V1H171 M172,0h-1H1H0v1v170v1h1h170h1v-1V1V0L172,0z"
               id="path86" /></g></g><text
           transform="matrix(1 5.460000e-03 -5.460000e-03 1 64.0738 111.6182)"
           class="st13 st6 st7"
           id="text88">3</text>
</g></g></switch></svg>
json_object* reply; if(!(data && data->state)) goto reply_done; // We opened the role, return the output reply = afb_wsj1_msg_object_j(msg); if(reply) { #ifdef DEBUG std::cerr << __FUNCTION__ << ": reply = " << \ json_object_to_json_string_ext(reply, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY) << \ std::endl; #endif struct json_object* response; int rc = json_object_object_get_ex(reply, "response", &response); if(rc) { struct json_object* val; rc = json_object_object_get_ex(response, "device_uri", &val); if (rc && json_object_get_string_len(val)) { const char* jres_pcm = json_object_get_string(val); data->output = jres_pcm; #ifdef DEBUG std::cerr << __FUNCTION__ << ": output = " << jres_pcm << std::endl; #endif } } } reply_done: // Signal reply is done data->cv.notify_one(); } static void *afb_loop_thread(struct sd_event* loop) { for(;;) sd_event_run(loop, 30000000); } static void *gst_loop_thread(GMainLoop *loop) { if(loop) g_main_loop_run(loop); } FilePlayer::FilePlayer(const int port, const std::string &token, const std::string &path, const std::string &role) : m_path(path), m_role(role) { std::string uri; if(sd_event_new(&m_afb_loop) < 0) { std::cerr << __FUNCTION__ << ": Failed to create event loop" << std::endl; return; } // Initialize interface for websocket m_itf.on_hangup = on_hangup; m_itf.on_call = on_call; m_itf.on_event = on_event; uri = "ws://localhost:" + std::to_string(port) + "/api?token=" + token; #ifdef DEBUG std::cerr << "Using URI: " << uri << std::endl; #endif m_ws = afb_ws_client_connect_wsj1(m_afb_loop, uri.c_str(), &m_itf, NULL); if(m_ws) { m_afb_thread = std::thread(afb_loop_thread, m_afb_loop); } else { std::cerr << __FUNCTION__ << ": Failed to create websocket connection" << std::endl; goto error; } // Initialize GStreamer gst_init(NULL, NULL); // Create elements we need m_playbin = gst_element_factory_make("playbin", "play"); m_alsa_sink = gst_element_factory_make("alsasink", NULL); if(!(m_playbin && m_alsa_sink)) goto error; // Set up bus callback m_bus = gst_pipeline_get_bus(GST_PIPELINE(m_playbin)); if(!m_bus) goto error; m_gst_loop = g_main_loop_new(NULL, FALSE); if(!m_gst_loop) goto error; gst_bus_add_watch(m_bus, gstreamer_bus_callback, this); // Start thread to run glib main loop for gstreamer bus m_gst_thread = std::thread(gst_loop_thread, m_gst_loop); m_valid = true; return; error: gst_object_unref(m_playbin); m_playbin = nullptr; gst_object_unref(m_alsa_sink); m_alsa_sink = nullptr; gst_object_unref(m_bus); m_bus = nullptr; if(m_gst_loop) { g_main_loop_quit(m_gst_loop); m_gst_loop = nullptr; } if(m_afb_loop) { sd_event_unref(m_afb_loop); m_afb_loop = nullptr; } return; } FilePlayer::~FilePlayer(void) { gst_element_set_state(m_playbin, GST_STATE_NULL); gst_object_unref(m_playbin); gst_object_unref(m_alsa_sink); gst_object_unref(m_bus); sd_event_unref(m_afb_loop); } void FilePlayer::play(bool loop) { std::string output; if(!m_valid || m_playing) return; if(set_role_state(true, &output) != 0) return; if(output.empty()) return; m_playing = true; m_looping = loop; g_object_set(m_alsa_sink, "device", output.c_str(), NULL); g_object_set(m_playbin, "audio-sink", m_alsa_sink, NULL); std::string uri = "file://" + m_path; g_object_set(m_playbin, "uri", uri.c_str(), NULL); // Start playback gst_element_set_state(m_playbin, GST_STATE_PLAYING); return; } void FilePlayer::stop(void) { if(!(m_valid && m_playing)) return; // Stop playback gst_element_set_state(m_playbin, GST_STATE_PAUSED); } gboolean FilePlayer::gstreamer_bus_callback(GstBus *bus, GstMessage *msg, gpointer data) { if(!data) return TRUE; return static_cast<FilePlayer*>(data)->bus_callback(bus, msg); } int FilePlayer::set_role_state(bool state, std::string *output) { if(!m_valid) return -1; set_role_data data; data.state = state; json_object *jsonData = json_object_new_object(); json_object_object_add(jsonData, "action", json_object_new_string(state ? "open" : "close")); int rc = afb_wsj1_call_j(m_ws, "ahl-4a", m_role.c_str(), jsonData, on_reply, (void*) &data); if(rc >= 0) { // Wait for response std::mutex m; std::unique_lock<std::mutex> lk(m); data.cv.wait(lk); if(state && output) *output = data.output; } else { std::cerr << __FUNCTION__ << ": Failed to call ahl-4a/" << m_role.c_str() << std::endl; } return rc; } gboolean FilePlayer::bus_callback(GstBus *bus, GstMessage *msg) { switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_EOS: #ifdef DEBUG std::cerr << __FUNCTION__ << ": GST_MESSAGE_EOS" << std::endl; #endif if(m_looping) { // restart playback if at end if (!gst_element_seek(m_playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { std::cerr << "Seek failed!" << std::endl; } } else { // Move stream to paused state since we're done gst_element_set_state(m_playbin, GST_STATE_PAUSED); } break; case GST_MESSAGE_STATE_CHANGED: { if((GstElement*) GST_MESSAGE_SRC(msg) != m_playbin) break; GstState old_state, new_state; gst_message_parse_state_changed(msg, &old_state, &new_state, NULL); #ifdef DEBUG std::cerr << __FUNCTION__ << ": GST_MESSAGE_STATE_CHANGE: " << (int) old_state << " to " << (int) new_state << std::endl; #endif if(old_state == GST_STATE_PLAYING && new_state == GST_STATE_PAUSED) { set_role_state(false); // Seek back to beginning so any subsequent play starts there if (!gst_element_seek(m_playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { std::cerr << "Seek failed!" << std::endl; } m_playing = false; } else if(old_state == GST_STATE_READY && new_state == GST_STATE_NULL) { // clean up g_main_loop_quit(m_gst_loop); } break; } default: break; } return TRUE; }