Added QtCamAutoFocus::setRegionOfInterest()
[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 = 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       qDebug() << "Error" << err->message << ":" << debug;
69
70       g_error_free(err);
71       g_free(debug);
72     }
73       break;
74
75     case GST_MESSAGE_WARNING: {
76       GError *err = NULL;
77       gchar *debug;
78
79       gst_message_parse_warning(message, &err, &debug);
80
81       qDebug() << "Warning" << err->message << ":" << debug;
82
83       g_error_free(err);
84       g_free(debug);
85     }
86       break;
87
88     case GST_MESSAGE_INFO: {
89       GError *err = NULL;
90       gchar *debug;
91
92       gst_message_parse_info(message, &err, &debug);
93
94       qDebug() << "Info" << err->message << ":" << debug;
95
96       g_error_free(err);
97       g_free(debug);
98     }
99       break;
100
101     case GST_MESSAGE_STATE_CHANGED: {
102       if (GST_ELEMENT(GST_MESSAGE_SRC(message)) != dev->cameraBin) {
103         break;
104       }
105
106       GstState oldState, newState, pending;
107       gst_message_parse_state_changed(message, &oldState, &newState, &pending);
108       if (oldState == GST_STATE_PAUSED && newState == GST_STATE_PLAYING) {
109         QMetaObject::invokeMethod(q_ptr, "started");
110       }
111       else if (oldState == GST_STATE_PLAYING && newState == GST_STATE_PAUSED) {
112         QMetaObject::invokeMethod(q_ptr, "stopping");
113       }
114       else if (oldState == GST_STATE_READY && newState == GST_STATE_NULL) {
115         QMetaObject::invokeMethod(q_ptr, "stopped");
116       }
117     }
118       break;
119
120     default:
121       break;
122     }
123   }
124
125   bool handleSyncMessage(GstMessage *message) {
126     QMutexLocker locker(&syncMutex);
127
128     if (handleMessage(message, syncHandlers) != 0) {
129       return true;
130     }
131
132     return false;
133   }
134
135   void addHandler(QtCamGStreamerMessageHandler *handler,
136                   QMultiMap<QString, QtCamGStreamerMessageHandler *>& map) {
137     if (!map.contains(handler->messageName(), handler)) {
138       map.insert(handler->messageName(), handler);
139       handler->setParent(q_ptr);
140     }
141   }
142
143   void removeHandler(QtCamGStreamerMessageHandler *handler,
144                      QMultiMap<QString, QtCamGStreamerMessageHandler *>& map) {
145     map.remove(handler->messageName(), handler);
146     handler->setParent(0);
147   }
148
149   QMutex syncMutex;
150
151   GstBus *bus;
152
153   QtCamDevicePrivate *dev;
154
155   guint watchId;
156
157   QtCamGStreamerMessageListener *q_ptr;
158 };
159
160 gboolean async_handler(GstBus *bus, GstMessage *message, gpointer data)
161 {
162   Q_UNUSED(bus);
163
164   QtCamGStreamerMessageListenerPrivate *d_ptr =
165     static_cast<QtCamGStreamerMessageListenerPrivate *>(data);
166
167   d_ptr->handleMessage(message);
168
169   // Call us again
170   return TRUE;
171 }
172
173 GstBusSyncReply sync_handler(GstBus *bus, GstMessage *message, gpointer data) {
174   Q_UNUSED(bus);
175
176   QtCamGStreamerMessageListenerPrivate *d_ptr =
177     static_cast<QtCamGStreamerMessageListenerPrivate *>(data);
178
179   if (d_ptr->handleSyncMessage(message)) {
180     gst_message_unref(message);
181     return GST_BUS_DROP;
182   }
183
184   return GST_BUS_PASS;
185 }
186
187 QtCamGStreamerMessageListener::QtCamGStreamerMessageListener(GstBus *bus,
188                                                              QtCamDevicePrivate *d,
189                                                              QObject *parent) :
190   QObject(parent), d_ptr(new QtCamGStreamerMessageListenerPrivate) {
191
192   d_ptr->dev = d;
193   d_ptr->bus = bus;
194   d_ptr->q_ptr = this;
195
196   d_ptr->watchId = gst_bus_add_watch(d_ptr->bus, async_handler, d_ptr);
197
198   gst_bus_set_sync_handler(d_ptr->bus, sync_handler, d_ptr);
199 }
200
201 QtCamGStreamerMessageListener::~QtCamGStreamerMessageListener() {
202   g_source_remove(d_ptr->watchId);
203   gst_bus_set_sync_handler(d_ptr->bus, NULL, NULL);
204
205   qDeleteAll(d_ptr->handlers);
206
207   d_ptr->syncMutex.lock();
208   qDeleteAll(d_ptr->syncHandlers);
209   d_ptr->syncMutex.unlock();
210
211   gst_object_unref(d_ptr->bus);
212
213   delete d_ptr; d_ptr = 0;
214 }
215
216 void QtCamGStreamerMessageListener::addHandler(QtCamGStreamerMessageHandler *handler) {
217   d_ptr->addHandler(handler, d_ptr->handlers);
218 }
219
220 void QtCamGStreamerMessageListener::removeHandler(QtCamGStreamerMessageHandler *handler) {
221   d_ptr->removeHandler(handler, d_ptr->handlers);
222 }
223
224 void QtCamGStreamerMessageListener::addSyncHandler(QtCamGStreamerMessageHandler *handler) {
225   QMutexLocker locker(&d_ptr->syncMutex);
226
227   d_ptr->addHandler(handler, d_ptr->syncHandlers);
228 }
229
230 void QtCamGStreamerMessageListener::removeSyncHandler(QtCamGStreamerMessageHandler *handler) {
231   QMutexLocker locker(&d_ptr->syncMutex);
232
233   d_ptr->removeHandler(handler, d_ptr->syncHandlers);
234 }
235
236 void QtCamGStreamerMessageListener::flushMessages() {
237   GstMessage *message = 0;
238
239   while ((message = gst_bus_pop(d_ptr->bus))) {
240     d_ptr->handleMessage(message);
241     gst_message_unref(message);
242   }
243 }