Don't reuse file names
[harmattan/cameraplus] / lib / qtcamgstreamermessagelistener.cpp
1 /*!
2  * This file is part of CameraPlus.
3  *
4  * Copyright (C) 2012-2013 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 = map.values(gst_structure_get_name(s));
44
45     foreach (QtCamGStreamerMessageHandler *handler, list) {
46       handler->handleMessage(message);
47     }
48
49     return list.size();
50   }
51
52   void handleMessage(GstMessage *message) {
53
54     switch (GST_MESSAGE_TYPE(message)) {
55     case GST_MESSAGE_ELEMENT:
56       handleMessage(message, handlers);
57       break;
58
59     case GST_MESSAGE_ERROR: {
60       GError *err = NULL;
61       gchar *debug;
62
63       gst_message_parse_error(message, &err, &debug);
64
65       QMetaObject::invokeMethod(q_ptr, "error", Q_ARG(QString, err->message),
66                                 Q_ARG(int, err->code), Q_ARG(QString, debug));
67
68 #if 0
69       qDebug() << "Error" << err->message << ":" << debug;
70 #endif
71
72       g_error_free(err);
73       g_free(debug);
74     }
75       break;
76
77     case GST_MESSAGE_WARNING: {
78       GError *err = NULL;
79       gchar *debug;
80
81       gst_message_parse_warning(message, &err, &debug);
82
83       qDebug() << "Warning" << err->message << ":" << debug;
84
85       g_error_free(err);
86       g_free(debug);
87     }
88       break;
89
90     case GST_MESSAGE_INFO: {
91       GError *err = NULL;
92       gchar *debug;
93
94       gst_message_parse_info(message, &err, &debug);
95
96       qDebug() << "Info" << err->message << ":" << debug;
97
98       g_error_free(err);
99       g_free(debug);
100     }
101       break;
102
103     case GST_MESSAGE_STATE_CHANGED: {
104       if (GST_ELEMENT(GST_MESSAGE_SRC(message)) != dev->cameraBin) {
105         break;
106       }
107
108       GstState oldState, newState, pending;
109       gst_message_parse_state_changed(message, &oldState, &newState, &pending);
110       if (oldState == GST_STATE_PAUSED && newState == GST_STATE_PLAYING) {
111         QMetaObject::invokeMethod(q_ptr, "started");
112       }
113       else if (oldState == GST_STATE_PLAYING && newState == GST_STATE_PAUSED) {
114         QMetaObject::invokeMethod(q_ptr, "stopping");
115       }
116       else if (oldState == GST_STATE_READY && newState == GST_STATE_NULL) {
117         QMetaObject::invokeMethod(q_ptr, "stopped");
118       }
119     }
120       break;
121
122     default:
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     // We need to pass the message.
183     // Issue is we have 2 video-done handlers, a sync and an async.
184     // If we drop the message then the async handler will never see it :|
185     return GST_BUS_PASS;
186   }
187
188   return GST_BUS_PASS;
189 }
190
191 QtCamGStreamerMessageListener::QtCamGStreamerMessageListener(GstBus *bus,
192                                                              QtCamDevicePrivate *d,
193                                                              QObject *parent) :
194   QObject(parent), d_ptr(new QtCamGStreamerMessageListenerPrivate) {
195
196   d_ptr->dev = d;
197   d_ptr->bus = bus;
198   d_ptr->q_ptr = this;
199
200   d_ptr->watchId = gst_bus_add_watch(d_ptr->bus, async_handler, d_ptr);
201
202   gst_bus_set_sync_handler(d_ptr->bus, sync_handler, d_ptr);
203 }
204
205 QtCamGStreamerMessageListener::~QtCamGStreamerMessageListener() {
206   g_source_remove(d_ptr->watchId);
207   gst_bus_set_sync_handler(d_ptr->bus, NULL, NULL);
208
209   qDeleteAll(d_ptr->handlers);
210
211   d_ptr->syncMutex.lock();
212   qDeleteAll(d_ptr->syncHandlers);
213   d_ptr->syncMutex.unlock();
214
215   gst_object_unref(d_ptr->bus);
216
217   delete d_ptr; d_ptr = 0;
218 }
219
220 void QtCamGStreamerMessageListener::addHandler(QtCamGStreamerMessageHandler *handler) {
221   d_ptr->addHandler(handler, d_ptr->handlers);
222 }
223
224 void QtCamGStreamerMessageListener::removeHandler(QtCamGStreamerMessageHandler *handler) {
225   d_ptr->removeHandler(handler, d_ptr->handlers);
226 }
227
228 void QtCamGStreamerMessageListener::addSyncHandler(QtCamGStreamerMessageHandler *handler) {
229   QMutexLocker locker(&d_ptr->syncMutex);
230
231   d_ptr->addHandler(handler, d_ptr->syncHandlers);
232 }
233
234 void QtCamGStreamerMessageListener::removeSyncHandler(QtCamGStreamerMessageHandler *handler) {
235   QMutexLocker locker(&d_ptr->syncMutex);
236
237   d_ptr->removeHandler(handler, d_ptr->syncHandlers);
238 }
239
240 void QtCamGStreamerMessageListener::flushMessages() {
241   GstMessage *message = 0;
242
243   while ((message = gst_bus_pop(d_ptr->bus))) {
244     d_ptr->handleMessage(message);
245     gst_message_unref(message);
246   }
247 }