43d3d3b04be3cbdd4e86a6203b0bf4382f447065
[harmattan/cameraplus] / lib / qtcamgstreamermessagelistener.cpp
1 #include "qtcamgstreamermessagelistener.h"
2 #include "qtcamgstreamermessagehandler.h"
3 #include <QMultiMap>
4 #include <QMutex>
5 #include <QDebug>
6 #include "qtcamdevice_p.h"
7
8 class QtCamGStreamerMessageListenerPrivate {
9 public:
10   QMultiMap<QString, QtCamGStreamerMessageHandler *> handlers;
11   QMultiMap<QString, QtCamGStreamerMessageHandler *> syncHandlers;
12
13   int handleMessage(GstMessage *message, QMultiMap<QString, QtCamGStreamerMessageHandler *>& map) {
14     const GstStructure *s = gst_message_get_structure(message);
15     if (!s) {
16       return 0;
17     }
18
19     QList<QtCamGStreamerMessageHandler *> list =
20       map.values(gst_structure_get_name(s));
21
22     foreach (QtCamGStreamerMessageHandler *handler, list) {
23       handler->handleMessage(message);
24     }
25
26     return list.size();
27   }
28
29   void handleMessage(GstMessage *message) {
30
31     switch (GST_MESSAGE_TYPE(message)) {
32     case GST_MESSAGE_ELEMENT:
33       handleMessage(message, handlers);
34       break;
35
36     case GST_MESSAGE_ERROR: {
37       GError *err = NULL;
38       gchar *debug;
39
40       gst_message_parse_error(message, &err, &debug);
41
42       QMetaObject::invokeMethod(q_ptr, "error", Q_ARG(QString, err->message),
43                                 Q_ARG(int, err->code), Q_ARG(QString, debug));
44
45       qDebug() << "Error" << err->message << ":" << debug;
46
47       g_error_free(err);
48       g_free(debug);
49     }
50       break;
51
52     case GST_MESSAGE_WARNING: {
53       GError *err = NULL;
54       gchar *debug;
55
56       gst_message_parse_warning(message, &err, &debug);
57
58       qDebug() << "Warning" << err->message << ":" << debug;
59
60       g_error_free(err);
61       g_free(debug);
62     }
63       break;
64
65     case GST_MESSAGE_INFO: {
66       GError *err = NULL;
67       gchar *debug;
68
69       gst_message_parse_info(message, &err, &debug);
70
71       qDebug() << "Info" << err->message << ":" << debug;
72
73       g_error_free(err);
74       g_free(debug);
75     }
76       break;
77
78     case GST_MESSAGE_STATE_CHANGED: {
79       if (GST_ELEMENT(GST_MESSAGE_SRC(message)) != dev->cameraBin) {
80         break;
81       }
82
83       GstState oldState, newState, pending;
84       gst_message_parse_state_changed(message, &oldState, &newState, &pending);
85       if (oldState == GST_STATE_PAUSED && newState == GST_STATE_PLAYING) {
86         QMetaObject::invokeMethod(q_ptr, "started");
87       }
88       else if (oldState == GST_STATE_PLAYING && newState == GST_STATE_PAUSED) {
89         QMetaObject::invokeMethod(q_ptr, "stopping");
90       }
91       else if (oldState == GST_STATE_READY && newState == GST_STATE_NULL) {
92         QMetaObject::invokeMethod(q_ptr, "stopped");
93       }
94     }
95       break;
96
97     default:
98       // TODO: other types
99       break;
100     }
101   }
102
103   bool handleSyncMessage(GstMessage *message) {
104     QMutexLocker locker(&syncMutex);
105
106     if (handleMessage(message, syncHandlers) != 0) {
107       return true;
108     }
109
110     return false;
111   }
112
113   void addHandler(QtCamGStreamerMessageHandler *handler,
114                   QMultiMap<QString, QtCamGStreamerMessageHandler *>& map) {
115     if (!map.contains(handler->messageName(), handler)) {
116       map.insert(handler->messageName(), handler);
117       handler->setParent(q_ptr);
118     }
119   }
120
121   void removeHandler(QtCamGStreamerMessageHandler *handler,
122                      QMultiMap<QString, QtCamGStreamerMessageHandler *>& map) {
123     map.remove(handler->messageName(), handler);
124     handler->setParent(0);
125   }
126
127   QMutex syncMutex;
128
129   GstBus *bus;
130
131   QtCamDevicePrivate *dev;
132
133   guint watchId;
134
135   QtCamGStreamerMessageListener *q_ptr;
136 };
137
138 gboolean async_handler(GstBus *bus, GstMessage *message, gpointer data)
139 {
140   Q_UNUSED(bus);
141
142   QtCamGStreamerMessageListenerPrivate *d_ptr =
143     static_cast<QtCamGStreamerMessageListenerPrivate *>(data);
144
145   d_ptr->handleMessage(message);
146
147   // Call us again
148   return TRUE;
149 }
150
151 GstBusSyncReply sync_handler(GstBus *bus, GstMessage *message, gpointer data) {
152   Q_UNUSED(bus);
153
154   QtCamGStreamerMessageListenerPrivate *d_ptr =
155     static_cast<QtCamGStreamerMessageListenerPrivate *>(data);
156
157   if (d_ptr->handleSyncMessage(message)) {
158     gst_message_unref(message);
159     return GST_BUS_DROP;
160   }
161
162   return GST_BUS_PASS;
163 }
164
165 QtCamGStreamerMessageListener::QtCamGStreamerMessageListener(GstBus *bus,
166                                                              QtCamDevicePrivate *d,
167                                                              QObject *parent) :
168   QObject(parent), d_ptr(new QtCamGStreamerMessageListenerPrivate) {
169
170   d_ptr->dev = d;
171   d_ptr->bus = bus;
172   d_ptr->q_ptr = this;
173
174   d_ptr->watchId = gst_bus_add_watch(d_ptr->bus, async_handler, d_ptr);
175
176   gst_bus_set_sync_handler(d_ptr->bus, sync_handler, d_ptr);
177 }
178
179 QtCamGStreamerMessageListener::~QtCamGStreamerMessageListener() {
180   g_source_remove(d_ptr->watchId);
181   gst_bus_set_sync_handler(d_ptr->bus, NULL, NULL);
182
183   qDeleteAll(d_ptr->handlers);
184
185   d_ptr->syncMutex.lock();
186   qDeleteAll(d_ptr->syncHandlers);
187   d_ptr->syncMutex.unlock();
188
189   gst_object_unref(d_ptr->bus);
190
191   delete d_ptr; d_ptr = 0;
192 }
193
194 void QtCamGStreamerMessageListener::addHandler(QtCamGStreamerMessageHandler *handler) {
195   d_ptr->addHandler(handler, d_ptr->handlers);
196 }
197
198 void QtCamGStreamerMessageListener::removeHandler(QtCamGStreamerMessageHandler *handler) {
199   d_ptr->removeHandler(handler, d_ptr->handlers);
200 }
201
202 void QtCamGStreamerMessageListener::addSyncHandler(QtCamGStreamerMessageHandler *handler) {
203   QMutexLocker locker(&d_ptr->syncMutex);
204
205   d_ptr->addHandler(handler, d_ptr->syncHandlers);
206 }
207
208 void QtCamGStreamerMessageListener::removeSyncHandler(QtCamGStreamerMessageHandler *handler) {
209   QMutexLocker locker(&d_ptr->syncMutex);
210
211   d_ptr->removeHandler(handler, d_ptr->syncHandlers);
212 }
213
214 void QtCamGStreamerMessageListener::flushMessages() {
215   GstMessage *message = 0;
216
217   while ((message = gst_bus_pop(d_ptr->bus))) {
218     d_ptr->handleMessage(message);
219     gst_message_unref(message);
220   }
221 }