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