Code cleanup
[harmattan/cameraplus] / lib / qtcamgstreamermessagelistener.cpp
1 /*!
2  * This file is part of CameraPlus.
3  *
4  * Copyright (C) 2012 Mohammed Sameer <msameer@foolab.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "qtcamgstreamermessagelistener.h"
22 #include "qtcamgstreamermessagehandler.h"
23 #include <QMultiMap>
24 #include <QMutex>
25 #include <QDebug>
26 #include "qtcamdevice_p.h"
27
28 class QtCamGStreamerMessageListenerPrivate {
29 public:
30   QMultiMap<QString, QtCamGStreamerMessageHandler *> handlers;
31   QMultiMap<QString, QtCamGStreamerMessageHandler *> syncHandlers;
32
33   int handleMessage(GstMessage *message, QMultiMap<QString, QtCamGStreamerMessageHandler *>& map) {
34     const GstStructure *s = gst_message_get_structure(message);
35     if (!s) {
36       return 0;
37     }
38
39 #if 0
40     qDebug() << "Message" << gst_structure_get_name(s);
41 #endif
42
43     QList<QtCamGStreamerMessageHandler *> list =
44       map.values(gst_structure_get_name(s));
45
46     foreach (QtCamGStreamerMessageHandler *handler, list) {
47       handler->handleMessage(message);
48     }
49
50     return list.size();
51   }
52
53   void handleMessage(GstMessage *message) {
54
55     switch (GST_MESSAGE_TYPE(message)) {
56     case GST_MESSAGE_ELEMENT:
57       handleMessage(message, handlers);
58       break;
59
60     case GST_MESSAGE_ERROR: {
61       GError *err = NULL;
62       gchar *debug;
63
64       gst_message_parse_error(message, &err, &debug);
65
66       QMetaObject::invokeMethod(q_ptr, "error", Q_ARG(QString, err->message),
67                                 Q_ARG(int, err->code), Q_ARG(QString, debug));
68
69       qDebug() << "Error" << err->message << ":" << debug;
70
71       g_error_free(err);
72       g_free(debug);
73     }
74       break;
75
76     case GST_MESSAGE_WARNING: {
77       GError *err = NULL;
78       gchar *debug;
79
80       gst_message_parse_warning(message, &err, &debug);
81
82       qDebug() << "Warning" << err->message << ":" << debug;
83
84       g_error_free(err);
85       g_free(debug);
86     }
87       break;
88
89     case GST_MESSAGE_INFO: {
90       GError *err = NULL;
91       gchar *debug;
92
93       gst_message_parse_info(message, &err, &debug);
94
95       qDebug() << "Info" << err->message << ":" << debug;
96
97       g_error_free(err);
98       g_free(debug);
99     }
100       break;
101
102     case GST_MESSAGE_STATE_CHANGED: {
103       if (GST_ELEMENT(GST_MESSAGE_SRC(message)) != dev->cameraBin) {
104         break;
105       }
106
107       GstState oldState, newState, pending;
108       gst_message_parse_state_changed(message, &oldState, &newState, &pending);
109       if (oldState == GST_STATE_PAUSED && newState == GST_STATE_PLAYING) {
110         QMetaObject::invokeMethod(q_ptr, "started");
111       }
112       else if (oldState == GST_STATE_PLAYING && newState == GST_STATE_PAUSED) {
113         QMetaObject::invokeMethod(q_ptr, "stopping");
114       }
115       else if (oldState == GST_STATE_READY && newState == GST_STATE_NULL) {
116         QMetaObject::invokeMethod(q_ptr, "stopped");
117       }
118     }
119       break;
120
121     default:
122       break;
123     }
124   }
125
126   bool handleSyncMessage(GstMessage *message) {
127     QMutexLocker locker(&syncMutex);
128
129     if (handleMessage(message, syncHandlers) != 0) {
130       return true;
131     }
132
133     return false;
134   }
135
136   void addHandler(QtCamGStreamerMessageHandler *handler,
137                   QMultiMap<QString, QtCamGStreamerMessageHandler *>& map) {
138     if (!map.contains(handler->messageName(), handler)) {
139       map.insert(handler->messageName(), handler);
140       handler->setParent(q_ptr);
141     }
142   }
143
144   void removeHandler(QtCamGStreamerMessageHandler *handler,
145                      QMultiMap<QString, QtCamGStreamerMessageHandler *>& map) {
146     map.remove(handler->messageName(), handler);
147     handler->setParent(0);
148   }
149
150   QMutex syncMutex;
151
152   GstBus *bus;
153
154   QtCamDevicePrivate *dev;
155
156   guint watchId;
157
158   QtCamGStreamerMessageListener *q_ptr;
159 };
160
161 gboolean async_handler(GstBus *bus, GstMessage *message, gpointer data)
162 {
163   Q_UNUSED(bus);
164
165   QtCamGStreamerMessageListenerPrivate *d_ptr =
166     static_cast<QtCamGStreamerMessageListenerPrivate *>(data);
167
168   d_ptr->handleMessage(message);
169
170   // Call us again
171   return TRUE;
172 }
173
174 GstBusSyncReply sync_handler(GstBus *bus, GstMessage *message, gpointer data) {
175   Q_UNUSED(bus);
176
177   QtCamGStreamerMessageListenerPrivate *d_ptr =
178     static_cast<QtCamGStreamerMessageListenerPrivate *>(data);
179
180   if (d_ptr->handleSyncMessage(message)) {
181     gst_message_unref(message);
182     return GST_BUS_DROP;
183   }
184
185   return GST_BUS_PASS;
186 }
187
188 QtCamGStreamerMessageListener::QtCamGStreamerMessageListener(GstBus *bus,
189                                                              QtCamDevicePrivate *d,
190                                                              QObject *parent) :
191   QObject(parent), d_ptr(new QtCamGStreamerMessageListenerPrivate) {
192
193   d_ptr->dev = d;
194   d_ptr->bus = bus;
195   d_ptr->q_ptr = this;
196
197   d_ptr->watchId = gst_bus_add_watch(d_ptr->bus, async_handler, d_ptr);
198
199   gst_bus_set_sync_handler(d_ptr->bus, sync_handler, d_ptr);
200 }
201
202 QtCamGStreamerMessageListener::~QtCamGStreamerMessageListener() {
203   g_source_remove(d_ptr->watchId);
204   gst_bus_set_sync_handler(d_ptr->bus, NULL, NULL);
205
206   qDeleteAll(d_ptr->handlers);
207
208   d_ptr->syncMutex.lock();
209   qDeleteAll(d_ptr->syncHandlers);
210   d_ptr->syncMutex.unlock();
211
212   gst_object_unref(d_ptr->bus);
213
214   delete d_ptr; d_ptr = 0;
215 }
216
217 void QtCamGStreamerMessageListener::addHandler(QtCamGStreamerMessageHandler *handler) {
218   d_ptr->addHandler(handler, d_ptr->handlers);
219 }
220
221 void QtCamGStreamerMessageListener::removeHandler(QtCamGStreamerMessageHandler *handler) {
222   d_ptr->removeHandler(handler, d_ptr->handlers);
223 }
224
225 void QtCamGStreamerMessageListener::addSyncHandler(QtCamGStreamerMessageHandler *handler) {
226   QMutexLocker locker(&d_ptr->syncMutex);
227
228   d_ptr->addHandler(handler, d_ptr->syncHandlers);
229 }
230
231 void QtCamGStreamerMessageListener::removeSyncHandler(QtCamGStreamerMessageHandler *handler) {
232   QMutexLocker locker(&d_ptr->syncMutex);
233
234   d_ptr->removeHandler(handler, d_ptr->syncHandlers);
235 }
236
237 void QtCamGStreamerMessageListener::flushMessages() {
238   GstMessage *message = 0;
239
240   while ((message = gst_bus_pop(d_ptr->bus))) {
241     d_ptr->handleMessage(message);
242     gst_message_unref(message);
243   }
244 }