6254fd688005f20efaf3665cebe145e5d10c9d2a
[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       // TODO: other types
123       break;
124     }
125   }
126
127   bool handleSyncMessage(GstMessage *message) {
128     QMutexLocker locker(&syncMutex);
129
130     if (handleMessage(message, syncHandlers) != 0) {
131       return true;
132     }
133
134     return false;
135   }
136
137   void addHandler(QtCamGStreamerMessageHandler *handler,
138                   QMultiMap<QString, QtCamGStreamerMessageHandler *>& map) {
139     if (!map.contains(handler->messageName(), handler)) {
140       map.insert(handler->messageName(), handler);
141       handler->setParent(q_ptr);
142     }
143   }
144
145   void removeHandler(QtCamGStreamerMessageHandler *handler,
146                      QMultiMap<QString, QtCamGStreamerMessageHandler *>& map) {
147     map.remove(handler->messageName(), handler);
148     handler->setParent(0);
149   }
150
151   QMutex syncMutex;
152
153   GstBus *bus;
154
155   QtCamDevicePrivate *dev;
156
157   guint watchId;
158
159   QtCamGStreamerMessageListener *q_ptr;
160 };
161
162 gboolean async_handler(GstBus *bus, GstMessage *message, gpointer data)
163 {
164   Q_UNUSED(bus);
165
166   QtCamGStreamerMessageListenerPrivate *d_ptr =
167     static_cast<QtCamGStreamerMessageListenerPrivate *>(data);
168
169   d_ptr->handleMessage(message);
170
171   // Call us again
172   return TRUE;
173 }
174
175 GstBusSyncReply sync_handler(GstBus *bus, GstMessage *message, gpointer data) {
176   Q_UNUSED(bus);
177
178   QtCamGStreamerMessageListenerPrivate *d_ptr =
179     static_cast<QtCamGStreamerMessageListenerPrivate *>(data);
180
181   if (d_ptr->handleSyncMessage(message)) {
182     gst_message_unref(message);
183     return GST_BUS_DROP;
184   }
185
186   return GST_BUS_PASS;
187 }
188
189 QtCamGStreamerMessageListener::QtCamGStreamerMessageListener(GstBus *bus,
190                                                              QtCamDevicePrivate *d,
191                                                              QObject *parent) :
192   QObject(parent), d_ptr(new QtCamGStreamerMessageListenerPrivate) {
193
194   d_ptr->dev = d;
195   d_ptr->bus = bus;
196   d_ptr->q_ptr = this;
197
198   d_ptr->watchId = gst_bus_add_watch(d_ptr->bus, async_handler, d_ptr);
199
200   gst_bus_set_sync_handler(d_ptr->bus, sync_handler, d_ptr);
201 }
202
203 QtCamGStreamerMessageListener::~QtCamGStreamerMessageListener() {
204   g_source_remove(d_ptr->watchId);
205   gst_bus_set_sync_handler(d_ptr->bus, NULL, NULL);
206
207   qDeleteAll(d_ptr->handlers);
208
209   d_ptr->syncMutex.lock();
210   qDeleteAll(d_ptr->syncHandlers);
211   d_ptr->syncMutex.unlock();
212
213   gst_object_unref(d_ptr->bus);
214
215   delete d_ptr; d_ptr = 0;
216 }
217
218 void QtCamGStreamerMessageListener::addHandler(QtCamGStreamerMessageHandler *handler) {
219   d_ptr->addHandler(handler, d_ptr->handlers);
220 }
221
222 void QtCamGStreamerMessageListener::removeHandler(QtCamGStreamerMessageHandler *handler) {
223   d_ptr->removeHandler(handler, d_ptr->handlers);
224 }
225
226 void QtCamGStreamerMessageListener::addSyncHandler(QtCamGStreamerMessageHandler *handler) {
227   QMutexLocker locker(&d_ptr->syncMutex);
228
229   d_ptr->addHandler(handler, d_ptr->syncHandlers);
230 }
231
232 void QtCamGStreamerMessageListener::removeSyncHandler(QtCamGStreamerMessageHandler *handler) {
233   QMutexLocker locker(&d_ptr->syncMutex);
234
235   d_ptr->removeHandler(handler, d_ptr->syncHandlers);
236 }
237
238 void QtCamGStreamerMessageListener::flushMessages() {
239   GstMessage *message = 0;
240
241   while ((message = gst_bus_pop(d_ptr->bus))) {
242     d_ptr->handleMessage(message);
243     gst_message_unref(message);
244   }
245 }