4 * Babeltrace Notification Iterator
6 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 #define BT_LOG_TAG "NOTIF-ITER"
29 #include <babeltrace/lib-logging-internal.h>
31 #include <babeltrace/compiler-internal.h>
32 #include <babeltrace/ref.h>
33 #include <babeltrace/ctf-ir/fields.h>
34 #include <babeltrace/ctf-ir/field-types.h>
35 #include <babeltrace/ctf-ir/field-types-internal.h>
36 #include <babeltrace/ctf-ir/event-internal.h>
37 #include <babeltrace/ctf-ir/packet-internal.h>
38 #include <babeltrace/ctf-ir/stream-internal.h>
39 #include <babeltrace/graph/connection.h>
40 #include <babeltrace/graph/connection-internal.h>
41 #include <babeltrace/graph/component.h>
42 #include <babeltrace/graph/component-source-internal.h>
43 #include <babeltrace/graph/component-class-internal.h>
44 #include <babeltrace/graph/component-class-sink-colander-internal.h>
45 #include <babeltrace/graph/component-sink.h>
46 #include <babeltrace/graph/notification.h>
47 #include <babeltrace/graph/notification-iterator.h>
48 #include <babeltrace/graph/notification-iterator-internal.h>
49 #include <babeltrace/graph/notification-internal.h>
50 #include <babeltrace/graph/notification-event.h>
51 #include <babeltrace/graph/notification-event-internal.h>
52 #include <babeltrace/graph/notification-packet.h>
53 #include <babeltrace/graph/notification-packet-internal.h>
54 #include <babeltrace/graph/notification-stream.h>
55 #include <babeltrace/graph/notification-stream-internal.h>
56 #include <babeltrace/graph/notification-discarded-elements-internal.h>
57 #include <babeltrace/graph/port.h>
58 #include <babeltrace/graph/graph-internal.h>
59 #include <babeltrace/types.h>
60 #include <babeltrace/assert-internal.h>
65 struct discarded_elements_state
{
66 struct bt_clock_value
*cur_begin
;
71 struct bt_stream
*stream
; /* owned by this */
72 struct bt_packet
*cur_packet
; /* owned by this */
73 struct discarded_elements_state discarded_packets_state
;
74 struct discarded_elements_state discarded_events_state
;
79 ACTION_TYPE_PUSH_NOTIF
,
80 ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
81 ACTION_TYPE_ADD_STREAM_STATE
,
82 ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
83 ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
84 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
,
85 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
,
89 enum action_type type
;
91 /* ACTION_TYPE_PUSH_NOTIF */
93 struct bt_notification
*notif
; /* owned by this */
96 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
98 struct bt_stream
*stream
; /* owned by this */
99 struct bt_component
*component
; /* owned by this */
100 struct bt_port
*port
; /* owned by this */
101 } map_port_to_comp_in_stream
;
103 /* ACTION_TYPE_ADD_STREAM_STATE */
105 struct bt_stream
*stream
; /* owned by this */
106 struct stream_state
*stream_state
; /* owned by this */
109 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
111 struct stream_state
*stream_state
; /* weak */
112 } set_stream_state_is_ended
;
114 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
116 struct stream_state
*stream_state
; /* weak */
117 struct bt_packet
*packet
; /* owned by this */
118 } set_stream_state_cur_packet
;
120 /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS */
121 /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS */
123 struct stream_state
*stream_state
; /* weak */
124 struct bt_clock_value
*cur_begin
; /* owned by this */
126 } update_stream_state_discarded_elements
;
131 void stream_destroy_listener(struct bt_stream
*stream
, void *data
)
133 struct bt_notification_iterator_private_connection
*iterator
= data
;
135 /* Remove associated stream state */
136 g_hash_table_remove(iterator
->stream_states
, stream
);
140 void destroy_stream_state(struct stream_state
*stream_state
)
146 BT_LOGV("Destroying stream state: stream-state-addr=%p", stream_state
);
147 BT_LOGV_STR("Putting stream state's current packet.");
148 bt_put(stream_state
->cur_packet
);
149 BT_LOGV_STR("Putting stream state's stream.");
150 bt_put(stream_state
->stream
);
151 bt_put(stream_state
->discarded_packets_state
.cur_begin
);
152 bt_put(stream_state
->discarded_events_state
.cur_begin
);
153 g_free(stream_state
);
157 void destroy_action(struct action
*action
)
161 switch (action
->type
) {
162 case ACTION_TYPE_PUSH_NOTIF
:
163 BT_PUT(action
->payload
.push_notif
.notif
);
165 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
166 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.stream
);
167 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.component
);
168 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.port
);
170 case ACTION_TYPE_ADD_STREAM_STATE
:
171 BT_PUT(action
->payload
.add_stream_state
.stream
);
172 destroy_stream_state(
173 action
->payload
.add_stream_state
.stream_state
);
174 action
->payload
.add_stream_state
.stream_state
= NULL
;
176 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
177 BT_PUT(action
->payload
.set_stream_state_cur_packet
.packet
);
179 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
181 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
:
182 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
:
183 BT_PUT(action
->payload
.update_stream_state_discarded_elements
.cur_begin
);
186 BT_LOGF("Unexpected action's type: type=%d", action
->type
);
192 void add_action(struct bt_notification_iterator_private_connection
*iterator
,
193 struct action
*action
)
195 g_array_append_val(iterator
->actions
, *action
);
199 void clear_actions(struct bt_notification_iterator_private_connection
*iterator
)
203 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
204 struct action
*action
= &g_array_index(iterator
->actions
,
207 destroy_action(action
);
210 g_array_set_size(iterator
->actions
, 0);
214 const char *action_type_string(enum action_type type
)
217 case ACTION_TYPE_PUSH_NOTIF
:
218 return "ACTION_TYPE_PUSH_NOTIF";
219 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
220 return "ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM";
221 case ACTION_TYPE_ADD_STREAM_STATE
:
222 return "ACTION_TYPE_ADD_STREAM_STATE";
223 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
224 return "ACTION_TYPE_SET_STREAM_STATE_IS_ENDED";
225 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
226 return "ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET";
227 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
:
228 return "ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS";
229 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
:
230 return "ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS";
237 void apply_actions(struct bt_notification_iterator_private_connection
*iterator
)
241 BT_LOGV("Applying notification's iterator current actions: "
242 "count=%u", iterator
->actions
->len
);
244 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
245 struct action
*action
= &g_array_index(iterator
->actions
,
248 BT_LOGV("Applying action: index=%zu, type=%s",
249 i
, action_type_string(action
->type
));
251 switch (action
->type
) {
252 case ACTION_TYPE_PUSH_NOTIF
:
253 /* Move notification to queue */
254 g_queue_push_head(iterator
->queue
,
255 action
->payload
.push_notif
.notif
);
256 bt_notification_freeze(
257 action
->payload
.push_notif
.notif
);
258 action
->payload
.push_notif
.notif
= NULL
;
260 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
261 bt_stream_map_component_to_port(
262 action
->payload
.map_port_to_comp_in_stream
.stream
,
263 action
->payload
.map_port_to_comp_in_stream
.component
,
264 action
->payload
.map_port_to_comp_in_stream
.port
);
266 case ACTION_TYPE_ADD_STREAM_STATE
:
267 /* Move stream state to hash table */
268 g_hash_table_insert(iterator
->stream_states
,
269 action
->payload
.add_stream_state
.stream
,
270 action
->payload
.add_stream_state
.stream_state
);
272 action
->payload
.add_stream_state
.stream_state
= NULL
;
274 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
276 * We know that this stream is ended. We need to
277 * remember this as long as the stream exists to
278 * enforce that the same stream does not end
281 * Here we add a destroy listener to the stream
282 * which we put after (becomes weak as the hash
283 * table key). If we were the last object to own
284 * this stream, the destroy listener is called
285 * when we call bt_put() which removes this
286 * stream state completely. This is important
287 * because the memory used by this stream object
288 * could be reused for another stream, and they
289 * must have different states.
291 bt_stream_add_destroy_listener(
292 action
->payload
.set_stream_state_is_ended
.stream_state
->stream
,
293 stream_destroy_listener
, iterator
);
294 action
->payload
.set_stream_state_is_ended
.stream_state
->is_ended
= BT_TRUE
;
295 BT_PUT(action
->payload
.set_stream_state_is_ended
.stream_state
->stream
);
297 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
298 /* Move packet to stream state's current packet */
299 BT_MOVE(action
->payload
.set_stream_state_cur_packet
.stream_state
->cur_packet
,
300 action
->payload
.set_stream_state_cur_packet
.packet
);
302 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
:
303 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
:
305 struct discarded_elements_state
*state
;
307 if (action
->type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
) {
308 state
= &action
->payload
.update_stream_state_discarded_elements
.stream_state
->discarded_packets_state
;
310 state
= &action
->payload
.update_stream_state_discarded_elements
.stream_state
->discarded_events_state
;
313 BT_MOVE(state
->cur_begin
,
314 action
->payload
.update_stream_state_discarded_elements
.cur_begin
);
315 state
->cur_count
= action
->payload
.update_stream_state_discarded_elements
.cur_count
;
319 BT_LOGF("Unexpected action's type: type=%d",
325 clear_actions(iterator
);
329 struct stream_state
*create_stream_state(struct bt_stream
*stream
)
331 struct stream_state
*stream_state
= g_new0(struct stream_state
, 1);
334 BT_LOGE_STR("Failed to allocate one stream state.");
339 * The packet index is a monotonic counter which may not start
340 * at 0 at the beginning of the stream. We therefore need to
341 * have an internal object initial state of -1ULL to distinguish
342 * between initial state and having seen a packet with
345 stream_state
->discarded_packets_state
.cur_count
= -1ULL;
348 * We keep a reference to the stream until we know it's ended
349 * because we need to be able to create an automatic "stream
350 * end" notification when the user's "next" method returns
351 * BT_NOTIFICATION_ITERATOR_STATUS_END.
353 * We put this reference when the stream is marked as ended.
355 stream_state
->stream
= bt_get(stream
);
356 BT_LOGV("Created stream state: stream-addr=%p, stream-name=\"%s\", "
357 "stream-state-addr=%p",
358 stream
, bt_stream_get_name(stream
), stream_state
);
365 void destroy_base_notification_iterator(struct bt_object
*obj
)
367 struct bt_notification_iterator
*iterator
=
368 container_of(obj
, struct bt_notification_iterator
, base
);
370 BT_LOGD_STR("Putting current notification.");
371 bt_put(iterator
->current_notification
);
376 void bt_private_connection_notification_iterator_destroy(struct bt_object
*obj
)
378 struct bt_notification_iterator_private_connection
*iterator
;
383 * The notification iterator's reference count is 0 if we're
384 * here. Increment it to avoid a double-destroy (possibly
385 * infinitely recursive). This could happen for example if the
386 * notification iterator's finalization function does bt_get()
387 * (or anything that causes bt_get() to be called) on itself
388 * (ref. count goes from 0 to 1), and then bt_put(): the
389 * reference count would go from 1 to 0 again and this function
390 * would be called again.
392 obj
->ref_count
.count
++;
393 iterator
= (void *) container_of(obj
, struct bt_notification_iterator
, base
);
394 BT_LOGD("Destroying private connection notification iterator object: addr=%p",
396 bt_private_connection_notification_iterator_finalize(iterator
);
398 if (iterator
->queue
) {
399 struct bt_notification
*notif
;
401 BT_LOGD("Putting notifications in queue.");
403 while ((notif
= g_queue_pop_tail(iterator
->queue
))) {
407 g_queue_free(iterator
->queue
);
410 if (iterator
->stream_states
) {
412 * Remove our destroy listener from each stream which
413 * has a state in this iterator. Otherwise the destroy
414 * listener would be called with an invalid/other
415 * notification iterator object.
417 GHashTableIter ht_iter
;
418 gpointer stream_gptr
, stream_state_gptr
;
420 g_hash_table_iter_init(&ht_iter
, iterator
->stream_states
);
422 while (g_hash_table_iter_next(&ht_iter
, &stream_gptr
, &stream_state_gptr
)) {
423 BT_ASSERT(stream_gptr
);
425 BT_LOGD_STR("Removing stream's destroy listener for notification iterator.");
426 bt_stream_remove_destroy_listener(
427 (void *) stream_gptr
, stream_destroy_listener
,
431 g_hash_table_destroy(iterator
->stream_states
);
434 if (iterator
->actions
) {
435 g_array_free(iterator
->actions
, TRUE
);
438 if (iterator
->connection
) {
440 * Remove ourself from the originating connection so
441 * that it does not try to finalize a dangling pointer
444 bt_connection_remove_iterator(iterator
->connection
, iterator
);
447 destroy_base_notification_iterator(obj
);
451 void bt_private_connection_notification_iterator_finalize(
452 struct bt_notification_iterator_private_connection
*iterator
)
454 struct bt_component_class
*comp_class
= NULL
;
455 bt_component_class_notification_iterator_finalize_method
456 finalize_method
= NULL
;
460 switch (iterator
->state
) {
461 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_NON_INITIALIZED
:
462 /* Skip user finalization if user initialization failed */
463 BT_LOGD("Not finalizing non-initialized notification iterator: "
464 "addr=%p", iterator
);
466 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
467 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
468 /* Already finalized */
469 BT_LOGD("Not finalizing notification iterator: already finalized: "
470 "addr=%p", iterator
);
476 BT_LOGD("Finalizing notification iterator: addr=%p", iterator
);
478 if (iterator
->state
== BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ENDED
) {
479 BT_LOGD("Updating notification iterator's state: "
480 "new-state=BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED");
481 iterator
->state
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
;
483 BT_LOGD("Updating notification iterator's state: "
484 "new-state=BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED");
485 iterator
->state
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED
;
488 BT_ASSERT(iterator
->upstream_component
);
489 comp_class
= iterator
->upstream_component
->class;
491 /* Call user-defined destroy method */
492 switch (comp_class
->type
) {
493 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
495 struct bt_component_class_source
*source_class
;
497 source_class
= container_of(comp_class
, struct bt_component_class_source
, parent
);
498 finalize_method
= source_class
->methods
.iterator
.finalize
;
501 case BT_COMPONENT_CLASS_TYPE_FILTER
:
503 struct bt_component_class_filter
*filter_class
;
505 filter_class
= container_of(comp_class
, struct bt_component_class_filter
, parent
);
506 finalize_method
= filter_class
->methods
.iterator
.finalize
;
514 if (finalize_method
) {
515 BT_LOGD("Calling user's finalization method: addr=%p",
518 bt_private_connection_private_notification_iterator_from_notification_iterator(iterator
));
521 iterator
->upstream_component
= NULL
;
522 iterator
->upstream_port
= NULL
;
523 BT_LOGD("Finalized notification iterator: addr=%p", iterator
);
527 void bt_private_connection_notification_iterator_set_connection(
528 struct bt_notification_iterator_private_connection
*iterator
,
529 struct bt_connection
*connection
)
532 iterator
->connection
= connection
;
533 BT_LOGV("Set notification iterator's connection: "
534 "iter-addr=%p, conn-addr=%p", iterator
, connection
);
538 int create_subscription_mask_from_notification_types(
539 struct bt_notification_iterator_private_connection
*iterator
,
540 const enum bt_notification_type
*notif_types
)
542 const enum bt_notification_type
*notif_type
;
545 BT_ASSERT(notif_types
);
546 iterator
->subscription_mask
= 0;
548 for (notif_type
= notif_types
;
549 *notif_type
!= BT_NOTIFICATION_TYPE_SENTINEL
;
551 switch (*notif_type
) {
552 case BT_NOTIFICATION_TYPE_ALL
:
553 iterator
->subscription_mask
|=
554 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
|
555 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
|
556 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
|
557 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
|
558 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
|
559 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
|
560 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS
|
561 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS
;
563 case BT_NOTIFICATION_TYPE_EVENT
:
564 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
566 case BT_NOTIFICATION_TYPE_INACTIVITY
:
567 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
569 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
570 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
572 case BT_NOTIFICATION_TYPE_STREAM_END
:
573 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
575 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
576 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
578 case BT_NOTIFICATION_TYPE_PACKET_END
:
579 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
581 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
582 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS
;
584 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
585 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS
;
592 BT_LOGV("Added notification type to subscription mask: "
594 bt_notification_type_string(*notif_type
),
595 iterator
->subscription_mask
);
603 void init_notification_iterator(struct bt_notification_iterator
*iterator
,
604 enum bt_notification_iterator_type type
,
605 bt_object_release_func destroy
)
607 bt_object_init(iterator
, destroy
);
608 iterator
->type
= type
;
612 enum bt_connection_status
bt_private_connection_notification_iterator_create(
613 struct bt_component
*upstream_comp
,
614 struct bt_port
*upstream_port
,
615 const enum bt_notification_type
*notification_types
,
616 struct bt_connection
*connection
,
617 struct bt_notification_iterator_private_connection
**user_iterator
)
619 enum bt_connection_status status
= BT_CONNECTION_STATUS_OK
;
620 enum bt_component_class_type type
;
621 struct bt_notification_iterator_private_connection
*iterator
= NULL
;
623 BT_ASSERT(upstream_comp
);
624 BT_ASSERT(upstream_port
);
625 BT_ASSERT(notification_types
);
626 BT_ASSERT(bt_port_is_connected(upstream_port
));
627 BT_ASSERT(user_iterator
);
628 BT_LOGD("Creating notification iterator on private connection: "
629 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
630 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
632 upstream_comp
, bt_component_get_name(upstream_comp
),
633 upstream_port
, bt_port_get_name(upstream_port
),
635 type
= bt_component_get_class_type(upstream_comp
);
636 BT_ASSERT(type
== BT_COMPONENT_CLASS_TYPE_SOURCE
||
637 type
== BT_COMPONENT_CLASS_TYPE_FILTER
);
638 iterator
= g_new0(struct bt_notification_iterator_private_connection
, 1);
640 BT_LOGE_STR("Failed to allocate one private connection notification iterator.");
641 status
= BT_CONNECTION_STATUS_NOMEM
;
645 init_notification_iterator((void *) iterator
,
646 BT_NOTIFICATION_ITERATOR_TYPE_PRIVATE_CONNECTION
,
647 bt_private_connection_notification_iterator_destroy
);
649 if (create_subscription_mask_from_notification_types(iterator
,
650 notification_types
)) {
651 BT_LOGW_STR("Cannot create subscription mask from notification types.");
652 status
= BT_CONNECTION_STATUS_INVALID
;
656 iterator
->stream_states
= g_hash_table_new_full(g_direct_hash
,
657 g_direct_equal
, NULL
, (GDestroyNotify
) destroy_stream_state
);
658 if (!iterator
->stream_states
) {
659 BT_LOGE_STR("Failed to allocate a GHashTable.");
660 status
= BT_CONNECTION_STATUS_NOMEM
;
664 iterator
->queue
= g_queue_new();
665 if (!iterator
->queue
) {
666 BT_LOGE_STR("Failed to allocate a GQueue.");
667 status
= BT_CONNECTION_STATUS_NOMEM
;
671 iterator
->actions
= g_array_new(FALSE
, FALSE
, sizeof(struct action
));
672 if (!iterator
->actions
) {
673 BT_LOGE_STR("Failed to allocate a GArray.");
674 status
= BT_CONNECTION_STATUS_NOMEM
;
678 iterator
->upstream_component
= upstream_comp
;
679 iterator
->upstream_port
= upstream_port
;
680 iterator
->connection
= connection
;
681 iterator
->state
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_NON_INITIALIZED
;
682 BT_LOGD("Created notification iterator: "
683 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
684 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
685 "conn-addr=%p, iter-addr=%p",
686 upstream_comp
, bt_component_get_name(upstream_comp
),
687 upstream_port
, bt_port_get_name(upstream_port
),
688 connection
, iterator
);
690 /* Move reference to user */
691 *user_iterator
= iterator
;
699 void *bt_private_connection_private_notification_iterator_get_user_data(
700 struct bt_private_connection_private_notification_iterator
*private_iterator
)
702 struct bt_notification_iterator_private_connection
*iterator
=
703 bt_private_connection_notification_iterator_borrow_from_private(private_iterator
);
705 return iterator
? iterator
->user_data
: NULL
;
708 enum bt_notification_iterator_status
709 bt_private_connection_private_notification_iterator_set_user_data(
710 struct bt_private_connection_private_notification_iterator
*private_iterator
,
713 enum bt_notification_iterator_status ret
=
714 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
715 struct bt_notification_iterator_private_connection
*iterator
=
716 bt_private_connection_notification_iterator_borrow_from_private(private_iterator
);
719 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
720 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
724 iterator
->user_data
= data
;
725 BT_LOGV("Set notification iterator's user data: "
726 "iter-addr=%p, user-data-addr=%p", iterator
, data
);
732 struct bt_notification
*bt_notification_iterator_get_notification(
733 struct bt_notification_iterator
*iterator
)
735 struct bt_notification
*notification
= NULL
;
738 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
742 notification
= bt_get(
743 bt_notification_iterator_borrow_current_notification(iterator
));
750 enum bt_private_connection_notification_iterator_notif_type
751 bt_notification_iterator_notif_type_from_notif_type(
752 enum bt_notification_type notif_type
)
754 enum bt_private_connection_notification_iterator_notif_type iter_notif_type
;
756 switch (notif_type
) {
757 case BT_NOTIFICATION_TYPE_EVENT
:
758 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
760 case BT_NOTIFICATION_TYPE_INACTIVITY
:
761 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
763 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
764 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
766 case BT_NOTIFICATION_TYPE_STREAM_END
:
767 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
769 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
770 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
772 case BT_NOTIFICATION_TYPE_PACKET_END
:
773 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
775 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
776 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS
;
778 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
779 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS
;
785 return iter_notif_type
;
789 bt_bool
validate_notification(
790 struct bt_notification_iterator_private_connection
*iterator
,
791 struct bt_notification
*notif
,
792 struct bt_stream
*notif_stream
,
793 struct bt_packet
*notif_packet
)
795 bt_bool is_valid
= BT_TRUE
;
796 struct stream_state
*stream_state
;
797 struct bt_port
*stream_comp_cur_port
;
799 BT_ASSERT(notif_stream
);
800 stream_comp_cur_port
=
801 bt_stream_port_for_component(notif_stream
,
802 iterator
->upstream_component
);
803 if (!stream_comp_cur_port
) {
805 * This is the first time this notification iterator
806 * bumps into this stream. Add an action to map the
807 * iterator's upstream component to the iterator's
808 * upstream port in this stream.
810 struct action action
= {
811 .type
= ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
812 .payload
.map_port_to_comp_in_stream
= {
813 .stream
= bt_get(notif_stream
),
814 .component
= bt_get(iterator
->upstream_component
),
815 .port
= bt_get(iterator
->upstream_port
),
819 add_action(iterator
, &action
);
821 if (stream_comp_cur_port
!= iterator
->upstream_port
) {
823 * It looks like two different ports of the same
824 * component are emitting notifications which
825 * have references to the same stream. This is
826 * bad: the API guarantees that it can never
829 BT_LOGW("Two different ports of the same component are emitting notifications which refer to the same stream: "
830 "stream-addr=%p, stream-name=\"%s\", "
831 "stream-comp-cur-port-addr=%p, "
832 "stream-comp-cur-port-name=%p, "
833 "iter-upstream-port-addr=%p, "
834 "iter-upstream-port-name=%s",
836 bt_stream_get_name(notif_stream
),
837 stream_comp_cur_port
,
838 bt_port_get_name(stream_comp_cur_port
),
839 iterator
->upstream_port
,
840 bt_port_get_name(iterator
->upstream_port
));
847 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
850 BT_LOGV("Stream state already exists: "
851 "stream-addr=%p, stream-name=\"%s\", "
852 "stream-state-addr=%p",
854 bt_stream_get_name(notif_stream
), stream_state
);
856 if (stream_state
->is_ended
) {
858 * There's a new notification which has a
859 * reference to a stream which, from this
860 * iterator's point of view, is ended ("end of
861 * stream" notification was returned). This is
862 * bad: the API guarantees that it can never
865 BT_LOGW("Stream is already ended: "
866 "stream-addr=%p, stream-name=\"%s\"",
868 bt_stream_get_name(notif_stream
));
873 switch (notif
->type
) {
874 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
876 * We already have a stream state, which means
877 * we already returned a "stream begin"
878 * notification: this is an invalid duplicate.
880 BT_LOGW("Duplicate stream beginning notification: "
881 "stream-addr=%p, stream-name=\"%s\"",
883 bt_stream_get_name(notif_stream
));
886 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
887 if (notif_packet
== stream_state
->cur_packet
) {
888 /* Duplicate "packet begin" notification */
889 BT_LOGW("Duplicate stream beginning notification: "
890 "stream-addr=%p, stream-name=\"%s\", "
893 bt_stream_get_name(notif_stream
),
909 bt_bool
is_subscribed_to_notification_type(
910 struct bt_notification_iterator_private_connection
*iterator
,
911 enum bt_notification_type notif_type
)
913 uint32_t iter_notif_type
=
914 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
917 return (iter_notif_type
& iterator
->subscription_mask
) ? BT_TRUE
: BT_FALSE
;
921 void add_action_push_notif(
922 struct bt_notification_iterator_private_connection
*iterator
,
923 struct bt_notification
*notif
)
925 struct action action
= {
926 .type
= ACTION_TYPE_PUSH_NOTIF
,
931 if (!is_subscribed_to_notification_type(iterator
, notif
->type
)) {
935 action
.payload
.push_notif
.notif
= bt_get(notif
);
936 add_action(iterator
, &action
);
937 BT_LOGV("Added \"push notification\" action: notif-addr=%p", notif
);
941 int add_action_push_notif_stream_begin(
942 struct bt_notification_iterator_private_connection
*iterator
,
943 struct bt_stream
*stream
)
946 struct bt_notification
*stream_begin_notif
= NULL
;
948 if (!is_subscribed_to_notification_type(iterator
,
949 BT_NOTIFICATION_TYPE_STREAM_BEGIN
)) {
950 BT_LOGV("Not adding \"push stream beginning notification\" action: "
951 "notification iterator is not subscribed: addr=%p",
957 stream_begin_notif
= bt_notification_stream_begin_create(stream
);
958 if (!stream_begin_notif
) {
959 BT_LOGE_STR("Cannot create stream beginning notification.");
963 add_action_push_notif(iterator
, stream_begin_notif
);
964 BT_LOGV("Added \"push stream beginning notification\" action: "
965 "stream-addr=%p, stream-name=\"%s\"",
966 stream
, bt_stream_get_name(stream
));
973 bt_put(stream_begin_notif
);
978 int add_action_push_notif_stream_end(
979 struct bt_notification_iterator_private_connection
*iterator
,
980 struct bt_stream
*stream
)
983 struct bt_notification
*stream_end_notif
= NULL
;
985 if (!is_subscribed_to_notification_type(iterator
,
986 BT_NOTIFICATION_TYPE_STREAM_END
)) {
987 BT_LOGV("Not adding \"push stream end notification\" action: "
988 "notification iterator is not subscribed: addr=%p",
994 stream_end_notif
= bt_notification_stream_end_create(stream
);
995 if (!stream_end_notif
) {
996 BT_LOGE_STR("Cannot create stream end notification.");
1000 add_action_push_notif(iterator
, stream_end_notif
);
1001 BT_LOGV("Added \"push stream end notification\" action: "
1002 "stream-addr=%p, stream-name=\"%s\"",
1003 stream
, bt_stream_get_name(stream
));
1010 bt_put(stream_end_notif
);
1015 int add_action_push_notif_packet_begin(
1016 struct bt_notification_iterator_private_connection
*iterator
,
1017 struct bt_packet
*packet
)
1020 struct bt_notification
*packet_begin_notif
= NULL
;
1022 if (!is_subscribed_to_notification_type(iterator
,
1023 BT_NOTIFICATION_TYPE_PACKET_BEGIN
)) {
1024 BT_LOGV("Not adding \"push packet beginning notification\" action: "
1025 "notification iterator is not subscribed: addr=%p",
1031 packet_begin_notif
= bt_notification_packet_begin_create(packet
);
1032 if (!packet_begin_notif
) {
1033 BT_LOGE_STR("Cannot create packet beginning notification.");
1037 add_action_push_notif(iterator
, packet_begin_notif
);
1038 BT_LOGV("Added \"push packet beginning notification\" action: "
1039 "packet-addr=%p", packet
);
1046 bt_put(packet_begin_notif
);
1051 int add_action_push_notif_packet_end(
1052 struct bt_notification_iterator_private_connection
*iterator
,
1053 struct bt_packet
*packet
)
1056 struct bt_notification
*packet_end_notif
= NULL
;
1058 if (!is_subscribed_to_notification_type(iterator
,
1059 BT_NOTIFICATION_TYPE_PACKET_END
)) {
1060 BT_LOGV("Not adding \"push packet end notification\" action: "
1061 "notification iterator is not subscribed: addr=%p",
1067 packet_end_notif
= bt_notification_packet_end_create(packet
);
1068 if (!packet_end_notif
) {
1069 BT_LOGE_STR("Cannot create packet end notification.");
1073 add_action_push_notif(iterator
, packet_end_notif
);
1074 BT_LOGV("Added \"push packet end notification\" action: "
1075 "packet-addr=%p", packet
);
1082 bt_put(packet_end_notif
);
1087 void add_action_set_stream_state_is_ended(
1088 struct bt_notification_iterator_private_connection
*iterator
,
1089 struct stream_state
*stream_state
)
1091 struct action action
= {
1092 .type
= ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
1093 .payload
.set_stream_state_is_ended
= {
1094 .stream_state
= stream_state
,
1098 BT_ASSERT(stream_state
);
1099 add_action(iterator
, &action
);
1100 BT_LOGV("Added \"set stream state's ended\" action: "
1101 "stream-state-addr=%p", stream_state
);
1105 void add_action_set_stream_state_cur_packet(
1106 struct bt_notification_iterator_private_connection
*iterator
,
1107 struct stream_state
*stream_state
,
1108 struct bt_packet
*packet
)
1110 struct action action
= {
1111 .type
= ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
1112 .payload
.set_stream_state_cur_packet
= {
1113 .stream_state
= stream_state
,
1114 .packet
= bt_get(packet
),
1118 BT_ASSERT(stream_state
);
1119 add_action(iterator
, &action
);
1120 BT_LOGV("Added \"set stream state's current packet\" action: "
1121 "stream-state-addr=%p, packet-addr=%p",
1122 stream_state
, packet
);
1126 void add_action_update_stream_state_discarded_elements(
1127 struct bt_notification_iterator_private_connection
*iterator
,
1128 enum action_type type
,
1129 struct stream_state
*stream_state
,
1130 struct bt_clock_value
*cur_begin
,
1133 struct action action
= {
1135 .payload
.update_stream_state_discarded_elements
= {
1136 .stream_state
= stream_state
,
1137 .cur_begin
= bt_get(cur_begin
),
1138 .cur_count
= cur_count
,
1142 BT_ASSERT(stream_state
);
1143 BT_ASSERT(type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
||
1144 type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
);
1145 add_action(iterator
, &action
);
1146 if (type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
) {
1147 BT_LOGV("Added \"update stream state's discarded packets\" action: "
1148 "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64
,
1149 stream_state
, cur_begin
, cur_count
);
1150 } else if (type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
) {
1151 BT_LOGV("Added \"update stream state's discarded events\" action: "
1152 "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64
,
1153 stream_state
, cur_begin
, cur_count
);
1158 int ensure_stream_state_exists(
1159 struct bt_notification_iterator_private_connection
*iterator
,
1160 struct bt_notification
*stream_begin_notif
,
1161 struct bt_stream
*notif_stream
,
1162 struct stream_state
**_stream_state
)
1165 struct stream_state
*stream_state
= NULL
;
1167 if (!notif_stream
) {
1169 * The notification does not reference any stream: no
1170 * need to get or create a stream state.
1175 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
1177 if (!stream_state
) {
1179 * This iterator did not bump into this stream yet:
1180 * create a stream state and a "stream begin"
1183 struct action action
= {
1184 .type
= ACTION_TYPE_ADD_STREAM_STATE
,
1185 .payload
.add_stream_state
= {
1186 .stream
= bt_get(notif_stream
),
1187 .stream_state
= NULL
,
1191 stream_state
= create_stream_state(notif_stream
);
1192 if (!stream_state
) {
1193 BT_LOGE_STR("Cannot create stream state.");
1197 action
.payload
.add_stream_state
.stream_state
= stream_state
;
1198 add_action(iterator
, &action
);
1200 if (stream_begin_notif
) {
1201 add_action_push_notif(iterator
, stream_begin_notif
);
1203 ret
= add_action_push_notif_stream_begin(iterator
,
1206 BT_LOGE_STR("Cannot add \"push stream beginning notification\" action.");
1214 destroy_stream_state(stream_state
);
1215 stream_state
= NULL
;
1219 *_stream_state
= stream_state
;
1224 struct bt_field
*get_struct_field_uint(struct bt_field
*struct_field
,
1225 const char *field_name
)
1227 struct bt_field
*field
= NULL
;
1228 struct bt_field_type
*ft
= NULL
;
1230 field
= bt_field_structure_get_field_by_name(struct_field
,
1233 BT_LOGV_STR("`%s` field does not exist.");
1237 if (!bt_field_is_integer(field
)) {
1238 BT_LOGV("Skipping `%s` field because its type is not an integer field type: "
1239 "field-addr=%p, ft-addr=%p, ft-id=%s", field_name
,
1240 field
, ft
, bt_field_type_id_string(
1241 bt_field_type_get_type_id(ft
)));
1246 ft
= bt_field_get_type(field
);
1249 if (bt_field_type_integer_is_signed(ft
)) {
1250 BT_LOGV("Skipping `%s` integer field because its type is signed: "
1251 "field-addr=%p, ft-addr=%p", field_name
, field
, ft
);
1262 uint64_t get_packet_context_events_discarded(struct bt_packet
*packet
)
1264 struct bt_field
*packet_context
= NULL
;
1265 struct bt_field
*field
= NULL
;
1266 uint64_t retval
= -1ULL;
1269 packet_context
= bt_packet_get_context(packet
);
1270 if (!packet_context
) {
1274 field
= get_struct_field_uint(packet_context
, "events_discarded");
1276 BT_LOGV("`events_discarded` field does not exist in packet's context field: "
1277 "packet-addr=%p, packet-context-field-addr=%p",
1278 packet
, packet_context
);
1282 BT_ASSERT(bt_field_is_integer(field
));
1283 ret
= bt_field_unsigned_integer_get_value(field
, &retval
);
1285 BT_LOGV("Cannot get raw value of packet's context field's `events_discarded` integer field: "
1286 "packet-addr=%p, field-addr=%p",
1293 bt_put(packet_context
);
1299 uint64_t get_packet_context_packet_seq_num(struct bt_packet
*packet
)
1301 struct bt_field
*packet_context
= NULL
;
1302 struct bt_field
*field
= NULL
;
1303 uint64_t retval
= -1ULL;
1306 packet_context
= bt_packet_get_context(packet
);
1307 if (!packet_context
) {
1311 field
= get_struct_field_uint(packet_context
, "packet_seq_num");
1313 BT_LOGV("`packet_seq_num` field does not exist in packet's context field: "
1314 "packet-addr=%p, packet-context-field-addr=%p",
1315 packet
, packet_context
);
1319 BT_ASSERT(bt_field_is_integer(field
));
1320 ret
= bt_field_unsigned_integer_get_value(field
, &retval
);
1322 BT_LOGV("Cannot get raw value of packet's context field's `packet_seq_num` integer field: "
1323 "packet-addr=%p, field-addr=%p",
1330 bt_put(packet_context
);
1336 int handle_discarded_packets(
1337 struct bt_notification_iterator_private_connection
*iterator
,
1338 struct bt_packet
*packet
,
1339 struct bt_clock_value
*ts_begin
,
1340 struct bt_clock_value
*ts_end
,
1341 struct stream_state
*stream_state
)
1343 struct bt_notification
*notif
= NULL
;
1345 uint64_t prev_count
, next_count
;
1348 next_count
= get_packet_context_packet_seq_num(packet
);
1349 if (next_count
== -1ULL) {
1351 * Stream does not have seqnum field, skip discarded
1356 prev_count
= stream_state
->discarded_packets_state
.cur_count
;
1358 if (prev_count
!= -1ULL) {
1359 if (next_count
< prev_count
) {
1360 BT_LOGW("Current value of packet's context field's `packet_seq_num` field is lesser than the previous value for the same stream: "
1361 "not updating the stream state's current value: "
1362 "packet-addr=%p, prev-count=%" PRIu64
", "
1363 "cur-count=%" PRIu64
,
1364 packet
, prev_count
, next_count
);
1367 if (next_count
== prev_count
) {
1368 BT_LOGW("Current value of packet's context field's `packet_seq_num` field is equal to the previous value for the same stream: "
1369 "not updating the stream state's current value: "
1370 "packet-addr=%p, prev-count=%" PRIu64
", "
1371 "cur-count=%" PRIu64
,
1372 packet
, prev_count
, next_count
);
1376 diff
= next_count
- prev_count
;
1379 * Add a discarded packets notification. The packets
1380 * are considered to be lost between the state's last time
1381 * and the current packet's beginning time.
1382 * The counter is expected to monotonically increase of
1383 * 1 for each packet. Therefore, the number of missing
1384 * packets is 'diff - 1'.
1386 notif
= bt_notification_discarded_elements_create(
1387 BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
,
1388 stream_state
->stream
,
1389 stream_state
->discarded_packets_state
.cur_begin
,
1390 ts_begin
, diff
- 1);
1392 BT_LOGE_STR("Cannot create discarded packets notification.");
1397 add_action_push_notif(iterator
, notif
);
1401 add_action_update_stream_state_discarded_elements(iterator
,
1402 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
,
1403 stream_state
, ts_end
, next_count
);
1411 int handle_discarded_events(
1412 struct bt_notification_iterator_private_connection
*iterator
,
1413 struct bt_packet
*packet
,
1414 struct bt_clock_value
*ts_begin
,
1415 struct bt_clock_value
*ts_end
,
1416 struct stream_state
*stream_state
)
1418 struct bt_notification
*notif
= NULL
;
1420 uint64_t next_count
;
1423 next_count
= get_packet_context_events_discarded(packet
);
1424 if (next_count
== -1ULL) {
1425 next_count
= stream_state
->discarded_events_state
.cur_count
;
1429 if (next_count
< stream_state
->discarded_events_state
.cur_count
) {
1430 BT_LOGW("Current value of packet's context field's `events_discarded` field is lesser than the previous value for the same stream: "
1431 "not updating the stream state's current value: "
1432 "packet-addr=%p, prev-count=%" PRIu64
", "
1433 "cur-count=%" PRIu64
,
1434 packet
, stream_state
->discarded_events_state
.cur_count
,
1439 diff
= next_count
- stream_state
->discarded_events_state
.cur_count
;
1442 * Add a discarded events notification. The events are
1443 * considered to be lost betweem the state's last time
1444 * and the current packet's end time.
1446 notif
= bt_notification_discarded_elements_create(
1447 BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
,
1448 stream_state
->stream
,
1449 stream_state
->discarded_events_state
.cur_begin
,
1452 BT_LOGE_STR("Cannot create discarded events notification.");
1457 add_action_push_notif(iterator
, notif
);
1461 add_action_update_stream_state_discarded_elements(iterator
,
1462 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
,
1463 stream_state
, ts_end
, next_count
);
1471 int get_field_clock_value(struct bt_field
*root_field
,
1472 const char *field_name
,
1473 struct bt_clock_value
**user_clock_val
)
1475 struct bt_field
*field
;
1476 struct bt_field_type
*ft
= NULL
;
1477 struct bt_clock_class
*clock_class
= NULL
;
1478 struct bt_clock_value
*clock_value
= NULL
;
1482 field
= get_struct_field_uint(root_field
, field_name
);
1484 /* Not an error: skip this */
1488 ft
= bt_field_get_type(field
);
1490 clock_class
= bt_field_type_integer_get_mapped_clock_class(ft
);
1492 BT_LOGW("Integer field type has no mapped clock class but it's expected to have one: "
1498 ret
= bt_field_unsigned_integer_get_value(field
, &val
);
1500 BT_LOGW("Cannot get integer field's raw value: "
1501 "field-addr=%p", field
);
1506 clock_value
= bt_clock_value_create(clock_class
, val
);
1508 BT_LOGE_STR("Cannot create clock value from clock class.");
1513 /* Move clock value to user */
1514 *user_clock_val
= clock_value
;
1520 bt_put(clock_class
);
1521 bt_put(clock_value
);
1526 int get_ts_begin_ts_end_from_packet(struct bt_packet
*packet
,
1527 struct bt_clock_value
**user_ts_begin
,
1528 struct bt_clock_value
**user_ts_end
)
1530 struct bt_field
*packet_context
= NULL
;
1531 struct bt_clock_value
*ts_begin
= NULL
;
1532 struct bt_clock_value
*ts_end
= NULL
;
1535 packet_context
= bt_packet_get_context(packet
);
1536 if (!packet_context
) {
1540 ret
= get_field_clock_value(packet_context
, "timestamp_begin",
1543 BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: "
1544 "packet-addr=%p, packet-context-field-addr=%p",
1545 packet
, packet_context
);
1549 ret
= get_field_clock_value(packet_context
, "timestamp_end",
1552 BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: "
1553 "packet-addr=%p, packet-context-field-addr=%p",
1554 packet
, packet_context
);
1558 /* Move clock values to user */
1559 *user_ts_begin
= ts_begin
;
1561 *user_ts_end
= ts_end
;
1565 bt_put(packet_context
);
1572 int handle_discarded_elements(
1573 struct bt_notification_iterator_private_connection
*iterator
,
1574 struct bt_packet
*packet
, struct stream_state
*stream_state
)
1576 struct bt_clock_value
*ts_begin
= NULL
;
1577 struct bt_clock_value
*ts_end
= NULL
;
1580 ret
= get_ts_begin_ts_end_from_packet(packet
, &ts_begin
, &ts_end
);
1582 BT_LOGW("Cannot get packet's beginning or end clock values: "
1583 "packet-addr=%p, ret=%d", packet
, ret
);
1588 ret
= handle_discarded_packets(iterator
, packet
, ts_begin
, ts_end
,
1591 BT_LOGW("Cannot handle discarded packets for packet: "
1592 "packet-addr=%p, ret=%d", packet
, ret
);
1597 ret
= handle_discarded_events(iterator
, packet
, ts_begin
, ts_end
,
1600 BT_LOGW("Cannot handle discarded events for packet: "
1601 "packet-addr=%p, ret=%d", packet
, ret
);
1613 int handle_packet_switch(
1614 struct bt_notification_iterator_private_connection
*iterator
,
1615 struct bt_notification
*packet_begin_notif
,
1616 struct bt_packet
*new_packet
,
1617 struct stream_state
*stream_state
)
1621 if (stream_state
->cur_packet
== new_packet
) {
1625 BT_LOGV("Handling packet switch: "
1626 "cur-packet-addr=%p, new-packet-addr=%p",
1627 stream_state
->cur_packet
, new_packet
);
1629 if (stream_state
->cur_packet
) {
1630 /* End of the current packet */
1631 ret
= add_action_push_notif_packet_end(iterator
,
1632 stream_state
->cur_packet
);
1634 BT_LOGE_STR("Cannot add \"push packet end notification\" action.");
1640 * Check the new packet's context fields for discarded packets
1641 * and events to emit those automatic notifications.
1643 ret
= handle_discarded_elements(iterator
, new_packet
, stream_state
);
1645 BT_LOGE_STR("Cannot handle discarded elements for new packet.");
1649 /* Beginning of the new packet */
1650 if (packet_begin_notif
) {
1651 add_action_push_notif(iterator
, packet_begin_notif
);
1652 } else if (new_packet
) {
1653 ret
= add_action_push_notif_packet_begin(iterator
,
1656 BT_LOGE_STR("Cannot add \"push packet beginning notification\" action.");
1661 add_action_set_stream_state_cur_packet(iterator
, stream_state
,
1673 int handle_notif_stream_begin(
1674 struct bt_notification_iterator_private_connection
*iterator
,
1675 struct bt_notification
*notif
,
1676 struct bt_stream
*notif_stream
)
1679 struct stream_state
*stream_state
;
1681 BT_ASSERT(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_BEGIN
);
1682 BT_ASSERT(notif_stream
);
1683 ret
= ensure_stream_state_exists(iterator
, notif
, notif_stream
,
1686 BT_LOGE_STR("Cannot ensure that stream state exists.");
1700 int handle_notif_stream_end(
1701 struct bt_notification_iterator_private_connection
*iterator
,
1702 struct bt_notification
*notif
,
1703 struct bt_stream
*notif_stream
)
1706 struct stream_state
*stream_state
;
1708 BT_ASSERT(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_END
);
1709 BT_ASSERT(notif_stream
);
1710 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1713 BT_LOGE_STR("Cannot ensure that stream state exists.");
1717 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1719 BT_LOGE_STR("Cannot handle packet switch.");
1723 add_action_push_notif(iterator
, notif
);
1724 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1735 int handle_notif_discarded_elements(
1736 struct bt_notification_iterator_private_connection
*iterator
,
1737 struct bt_notification
*notif
,
1738 struct bt_stream
*notif_stream
)
1741 struct stream_state
*stream_state
;
1743 BT_ASSERT(notif
->type
== BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
||
1744 notif
->type
== BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
);
1745 BT_ASSERT(notif_stream
);
1746 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1749 BT_LOGE_STR("Cannot ensure that stream state exists.");
1753 add_action_push_notif(iterator
, notif
);
1764 int handle_notif_packet_begin(
1765 struct bt_notification_iterator_private_connection
*iterator
,
1766 struct bt_notification
*notif
,
1767 struct bt_stream
*notif_stream
,
1768 struct bt_packet
*notif_packet
)
1771 struct stream_state
*stream_state
;
1773 BT_ASSERT(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_BEGIN
);
1774 BT_ASSERT(notif_packet
);
1775 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1778 BT_LOGE_STR("Cannot ensure that stream state exists.");
1782 ret
= handle_packet_switch(iterator
, notif
, notif_packet
, stream_state
);
1784 BT_LOGE_STR("Cannot handle packet switch.");
1798 int handle_notif_packet_end(
1799 struct bt_notification_iterator_private_connection
*iterator
,
1800 struct bt_notification
*notif
,
1801 struct bt_stream
*notif_stream
,
1802 struct bt_packet
*notif_packet
)
1805 struct stream_state
*stream_state
;
1807 BT_ASSERT(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_END
);
1808 BT_ASSERT(notif_packet
);
1809 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1812 BT_LOGE_STR("Cannot ensure that stream state exists.");
1816 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1818 BT_LOGE_STR("Cannot handle packet switch.");
1822 /* End of the current packet */
1823 add_action_push_notif(iterator
, notif
);
1824 add_action_set_stream_state_cur_packet(iterator
, stream_state
, NULL
);
1835 int handle_notif_event(
1836 struct bt_notification_iterator_private_connection
*iterator
,
1837 struct bt_notification
*notif
,
1838 struct bt_stream
*notif_stream
,
1839 struct bt_packet
*notif_packet
)
1842 struct stream_state
*stream_state
;
1844 BT_ASSERT(notif
->type
== BT_NOTIFICATION_TYPE_EVENT
);
1845 BT_ASSERT(notif_packet
);
1846 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1849 BT_LOGE_STR("Cannot ensure that stream state exists.");
1853 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1855 BT_LOGE_STR("Cannot handle packet switch.");
1859 add_action_push_notif(iterator
, notif
);
1870 int enqueue_notification_and_automatic(
1871 struct bt_notification_iterator_private_connection
*iterator
,
1872 struct bt_notification
*notif
)
1875 struct bt_event
*notif_event
= NULL
;
1876 struct bt_stream
*notif_stream
= NULL
;
1877 struct bt_packet
*notif_packet
= NULL
;
1881 BT_LOGV("Enqueuing user notification and automatic notifications: "
1882 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1884 // TODO: Skip most of this if the iterator is only subscribed
1885 // to event/inactivity notifications.
1887 /* Get the stream and packet referred by the notification */
1888 switch (notif
->type
) {
1889 case BT_NOTIFICATION_TYPE_EVENT
:
1890 notif_event
= bt_notification_event_borrow_event(notif
);
1891 BT_ASSERT(notif_event
);
1892 notif_packet
= bt_event_borrow_packet(notif_event
);
1893 BT_ASSERT(notif_packet
);
1895 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1897 bt_notification_stream_begin_borrow_stream(notif
);
1898 BT_ASSERT(notif_stream
);
1900 case BT_NOTIFICATION_TYPE_STREAM_END
:
1901 notif_stream
= bt_notification_stream_end_borrow_stream(notif
);
1902 BT_ASSERT(notif_stream
);
1904 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1906 bt_notification_packet_begin_borrow_packet(notif
);
1907 BT_ASSERT(notif_packet
);
1909 case BT_NOTIFICATION_TYPE_PACKET_END
:
1910 notif_packet
= bt_notification_packet_end_borrow_packet(notif
);
1911 BT_ASSERT(notif_packet
);
1913 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1918 * Invalid type of notification. Only the notification
1919 * types above are allowed to be returned by a user
1922 BT_LOGF("Unexpected notification type at this point: "
1923 "notif-addr=%p, notif-type=%s", notif
,
1924 bt_notification_type_string(notif
->type
));
1929 notif_stream
= bt_packet_borrow_stream(notif_packet
);
1930 BT_ASSERT(notif_stream
);
1933 if (!notif_stream
) {
1935 * The notification has no reference to a stream: it
1936 * cannot cause the creation of automatic notifications.
1938 BT_LOGV_STR("Notification has no reference to any stream: skipping automatic notification generation.");
1942 if (!validate_notification(iterator
, notif
, notif_stream
,
1944 BT_LOGW_STR("Invalid notification.");
1949 switch (notif
->type
) {
1950 case BT_NOTIFICATION_TYPE_EVENT
:
1951 ret
= handle_notif_event(iterator
, notif
, notif_stream
,
1954 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1955 ret
= handle_notif_stream_begin(iterator
, notif
, notif_stream
);
1957 case BT_NOTIFICATION_TYPE_STREAM_END
:
1958 ret
= handle_notif_stream_end(iterator
, notif
, notif_stream
);
1960 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1961 ret
= handle_notif_packet_begin(iterator
, notif
, notif_stream
,
1964 case BT_NOTIFICATION_TYPE_PACKET_END
:
1965 ret
= handle_notif_packet_end(iterator
, notif
, notif_stream
,
1968 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
1969 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
1970 ret
= handle_notif_discarded_elements(iterator
, notif
,
1973 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1974 add_action_push_notif(iterator
, notif
);
1981 BT_LOGW_STR("Failed to handle notification for automatic notification generation.");
1985 apply_actions(iterator
);
1986 BT_LOGV("Enqueued user notification and automatic notifications: "
1987 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1998 int handle_end(struct bt_notification_iterator_private_connection
*iterator
)
2000 GHashTableIter stream_state_iter
;
2001 gpointer stream_gptr
, stream_state_gptr
;
2004 BT_LOGV("Handling end of iteration: addr=%p", iterator
);
2007 * Emit a "stream end" notification for each non-ended stream
2008 * known by this iterator and mark them as ended.
2010 g_hash_table_iter_init(&stream_state_iter
, iterator
->stream_states
);
2012 while (g_hash_table_iter_next(&stream_state_iter
, &stream_gptr
,
2013 &stream_state_gptr
)) {
2014 struct stream_state
*stream_state
= stream_state_gptr
;
2016 BT_ASSERT(stream_state_gptr
);
2018 if (stream_state
->is_ended
) {
2022 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
2024 BT_LOGE_STR("Cannot handle packet switch.");
2028 ret
= add_action_push_notif_stream_end(iterator
, stream_gptr
);
2030 BT_LOGE_STR("Cannot add \"push stream end notification\" action.");
2034 add_action_set_stream_state_is_ended(iterator
, stream_state
);
2037 apply_actions(iterator
);
2038 BT_LOGV("Handled end of iteration: addr=%p", iterator
);
2049 enum bt_notification_iterator_status
ensure_queue_has_notifications(
2050 struct bt_notification_iterator_private_connection
*iterator
)
2052 struct bt_private_connection_private_notification_iterator
*priv_iterator
=
2053 bt_private_connection_private_notification_iterator_from_notification_iterator(iterator
);
2054 bt_component_class_notification_iterator_next_method next_method
= NULL
;
2055 struct bt_notification_iterator_next_method_return next_return
= {
2056 .status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
,
2057 .notification
= NULL
,
2059 enum bt_notification_iterator_status status
=
2060 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
2063 BT_ASSERT(iterator
);
2064 BT_LOGD("Ensuring that notification iterator's queue has at least one notification: "
2065 "iter-addr=%p, queue-size=%u, iter-state=%s",
2066 iterator
, iterator
->queue
->length
,
2067 bt_private_connection_notification_iterator_state_string(iterator
->state
));
2069 if (iterator
->queue
->length
> 0) {
2071 * We already have enough. Even if this notification
2072 * iterator is finalized, its user can still flush its
2073 * current queue's content by calling its "next" method
2074 * since this content is local and has no impact on what
2075 * used to be the iterator's upstream component.
2077 BT_LOGD_STR("Queue already has at least one notification.");
2081 switch (iterator
->state
) {
2082 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
2083 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
2084 BT_LOGD_STR("Notification iterator's \"next\" called, but it is finalized.");
2085 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
2087 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ENDED
:
2088 BT_LOGD_STR("Notification iterator is ended.");
2089 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
2095 BT_ASSERT(iterator
->upstream_component
);
2096 BT_ASSERT(iterator
->upstream_component
->class);
2098 /* Pick the appropriate "next" method */
2099 switch (iterator
->upstream_component
->class->type
) {
2100 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
2102 struct bt_component_class_source
*source_class
=
2103 container_of(iterator
->upstream_component
->class,
2104 struct bt_component_class_source
, parent
);
2106 BT_ASSERT(source_class
->methods
.iterator
.next
);
2107 next_method
= source_class
->methods
.iterator
.next
;
2110 case BT_COMPONENT_CLASS_TYPE_FILTER
:
2112 struct bt_component_class_filter
*filter_class
=
2113 container_of(iterator
->upstream_component
->class,
2114 struct bt_component_class_filter
, parent
);
2116 BT_ASSERT(filter_class
->methods
.iterator
.next
);
2117 next_method
= filter_class
->methods
.iterator
.next
;
2125 * Call the user's "next" method to get the next notification
2128 BT_ASSERT(next_method
);
2130 while (iterator
->queue
->length
== 0) {
2131 BT_LOGD_STR("Calling user's \"next\" method.");
2132 next_return
= next_method(priv_iterator
);
2133 BT_LOGD("User method returned: status=%s",
2134 bt_notification_iterator_status_string(next_return
.status
));
2135 if (next_return
.status
< 0) {
2136 BT_LOGW_STR("User method failed.");
2137 status
= next_return
.status
;
2141 if (iterator
->state
== BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED
||
2142 iterator
->state
== BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
) {
2144 * The user's "next" method, somehow, cancelled
2145 * its own notification iterator. This can
2146 * happen, for example, when the user's method
2147 * removes the port on which there's the
2148 * connection from which the iterator was
2149 * created. In this case, said connection is
2150 * ended, and all its notification iterators are
2153 * Only bt_put() the returned notification if
2155 * BT_NOTIFICATION_ITERATOR_STATUS_OK because
2156 * otherwise this field could be garbage.
2158 if (next_return
.status
==
2159 BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
2160 bt_put(next_return
.notification
);
2163 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
2167 switch (next_return
.status
) {
2168 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
2169 ret
= handle_end(iterator
);
2171 BT_LOGW_STR("Cannot handle end of iteration.");
2172 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
2176 BT_ASSERT(iterator
->state
==
2177 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ACTIVE
);
2178 iterator
->state
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ENDED
;
2180 if (iterator
->queue
->length
== 0) {
2181 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
2184 BT_LOGD("Set new status: status=%s",
2185 bt_notification_iterator_status_string(status
));
2187 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
:
2188 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
2190 case BT_NOTIFICATION_ITERATOR_STATUS_OK
:
2191 if (!next_return
.notification
) {
2192 BT_LOGW_STR("User method returned BT_NOTIFICATION_ITERATOR_STATUS_OK, but notification is NULL.");
2193 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
2198 * Ignore some notifications which are always
2199 * automatically generated by the notification
2200 * iterator to make sure they have valid values.
2202 switch (next_return
.notification
->type
) {
2203 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
2204 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
2205 BT_LOGV("Ignoring discarded elements notification returned by notification iterator's \"next\" method: "
2207 bt_notification_type_string(next_return
.notification
->type
));
2208 BT_PUT(next_return
.notification
);
2215 * We know the notification is valid. Before we
2216 * push it to the head of the queue, push the
2217 * appropriate automatic notifications if any.
2219 ret
= enqueue_notification_and_automatic(iterator
,
2220 next_return
.notification
);
2221 BT_PUT(next_return
.notification
);
2223 BT_LOGW("Cannot enqueue notification and automatic notifications.");
2224 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
2229 /* Unknown non-error status */
2238 enum bt_notification_iterator_status
2239 bt_notification_iterator_next(struct bt_notification_iterator
*iterator
)
2241 enum bt_notification_iterator_status status
;
2244 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
2245 status
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
2249 BT_LOGD("Notification iterator's \"next\": iter-addr=%p", iterator
);
2251 switch (iterator
->type
) {
2252 case BT_NOTIFICATION_ITERATOR_TYPE_PRIVATE_CONNECTION
:
2254 struct bt_notification_iterator_private_connection
*priv_conn_iter
=
2256 struct bt_notification
*notif
;
2259 * Make sure that the iterator's queue contains at least
2262 status
= ensure_queue_has_notifications(priv_conn_iter
);
2263 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
2268 * Move the notification at the tail of the queue to the
2269 * iterator's current notification.
2271 BT_ASSERT(priv_conn_iter
->queue
->length
> 0);
2272 notif
= g_queue_pop_tail(priv_conn_iter
->queue
);
2273 bt_notification_iterator_replace_current_notification(
2278 case BT_NOTIFICATION_ITERATOR_TYPE_OUTPUT_PORT
:
2280 struct bt_notification_iterator_output_port
*out_port_iter
=
2284 * Keep current notification in case there's an error:
2285 * restore this notification so that the current
2286 * notification is not changed from the user's point of
2289 struct bt_notification
*old_notif
=
2290 bt_get(bt_notification_iterator_borrow_current_notification(iterator
));
2291 enum bt_graph_status graph_status
;
2294 * Put current notification since it's possibly
2295 * about to be replaced by a new one by the
2298 bt_notification_iterator_replace_current_notification(
2300 graph_status
= bt_graph_consume_sink_no_check(
2301 out_port_iter
->graph
,
2302 out_port_iter
->colander
);
2303 switch (graph_status
) {
2304 case BT_GRAPH_STATUS_CANCELED
:
2305 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
2307 case BT_GRAPH_STATUS_AGAIN
:
2308 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
2310 case BT_GRAPH_STATUS_END
:
2311 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
2313 case BT_GRAPH_STATUS_NOMEM
:
2314 status
= BT_NOTIFICATION_ITERATOR_STATUS_NOMEM
;
2316 case BT_GRAPH_STATUS_OK
:
2317 status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
;
2318 BT_ASSERT(bt_notification_iterator_borrow_current_notification(iterator
));
2322 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
2325 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
2326 /* Error/exception: restore old notification */
2327 bt_notification_iterator_replace_current_notification(
2328 iterator
, old_notif
);
2335 BT_LOGF("Unknown notification iterator type: addr=%p, type=%d",
2336 iterator
, iterator
->type
);
2344 struct bt_component
*bt_private_connection_notification_iterator_get_component(
2345 struct bt_notification_iterator
*iterator
)
2347 struct bt_component
*comp
= NULL
;
2348 struct bt_notification_iterator_private_connection
*iter_priv_conn
;
2351 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
2355 if (iterator
->type
!= BT_NOTIFICATION_ITERATOR_TYPE_PRIVATE_CONNECTION
) {
2356 BT_LOGW_STR("Invalid parameter: notification iterator was not created from a private connection.");
2360 iter_priv_conn
= (void *) iterator
;
2361 comp
= bt_get(iter_priv_conn
->upstream_component
);
2367 struct bt_private_component
*
2368 bt_private_connection_private_notification_iterator_get_private_component(
2369 struct bt_private_connection_private_notification_iterator
*private_iterator
)
2371 return bt_private_component_from_component(
2372 bt_private_connection_notification_iterator_get_component(
2373 (void *) bt_private_connection_notification_iterator_borrow_from_private(private_iterator
)));
2377 void bt_output_port_notification_iterator_destroy(struct bt_object
*obj
)
2379 struct bt_notification_iterator_output_port
*iterator
=
2380 (void *) container_of(obj
, struct bt_notification_iterator
, base
);
2382 BT_LOGD("Destroying output port notification iterator object: addr=%p",
2384 BT_LOGD_STR("Putting graph.");
2385 bt_put(iterator
->graph
);
2386 BT_LOGD_STR("Putting output port.");
2387 bt_put(iterator
->output_port
);
2388 BT_LOGD_STR("Putting colander sink component.");
2389 bt_put(iterator
->colander
);
2390 destroy_base_notification_iterator(obj
);
2393 struct bt_notification_iterator
*bt_output_port_notification_iterator_create(
2394 struct bt_port
*output_port
,
2395 const char *colander_component_name
,
2396 const enum bt_notification_type
*notification_types
)
2398 struct bt_notification_iterator
*iterator_base
= NULL
;
2399 struct bt_notification_iterator_output_port
*iterator
= NULL
;
2400 struct bt_component_class
*colander_comp_cls
= NULL
;
2401 struct bt_component
*output_port_comp
= NULL
;
2402 struct bt_component
*colander_comp
;
2403 struct bt_graph
*graph
= NULL
;
2404 enum bt_graph_status graph_status
;
2405 const char *colander_comp_name
;
2406 struct bt_port
*colander_in_port
= NULL
;
2407 struct bt_component_class_sink_colander_data colander_data
;
2410 BT_LOGW_STR("Invalid parameter: port is NULL.");
2414 if (bt_port_get_type(output_port
) != BT_PORT_TYPE_OUTPUT
) {
2415 BT_LOGW_STR("Invalid parameter: port is not an output port.");
2419 output_port_comp
= bt_port_get_component(output_port
);
2420 if (!output_port_comp
) {
2421 BT_LOGW("Cannot get output port's component: "
2422 "port-addr=%p, port-name=\"%s\"",
2423 output_port
, bt_port_get_name(output_port
));
2427 graph
= bt_component_get_graph(output_port_comp
);
2430 /* Create notification iterator */
2431 BT_LOGD("Creating notification iterator on output port: "
2432 "comp-addr=%p, comp-name\"%s\", port-addr=%p, port-name=\"%s\"",
2433 output_port_comp
, bt_component_get_name(output_port_comp
),
2434 output_port
, bt_port_get_name(output_port
));
2435 iterator
= g_new0(struct bt_notification_iterator_output_port
, 1);
2437 BT_LOGE_STR("Failed to allocate one output port notification iterator.");
2441 init_notification_iterator((void *) iterator
,
2442 BT_NOTIFICATION_ITERATOR_TYPE_OUTPUT_PORT
,
2443 bt_output_port_notification_iterator_destroy
);
2445 /* Create colander component */
2446 colander_comp_cls
= bt_component_class_sink_colander_get();
2447 if (!colander_comp_cls
) {
2448 BT_LOGW("Cannot get colander sink component class.");
2452 BT_MOVE(iterator
->graph
, graph
);
2453 iterator_base
= (void *) iterator
;
2454 colander_comp_name
=
2455 colander_component_name
? colander_component_name
: "colander";
2456 colander_data
.notification
= &iterator_base
->current_notification
;
2457 colander_data
.notification_types
= notification_types
;
2458 graph_status
= bt_graph_add_component_with_init_method_data(
2459 iterator
->graph
, colander_comp_cls
, colander_comp_name
,
2460 NULL
, &colander_data
, &iterator
->colander
);
2461 if (graph_status
!= BT_GRAPH_STATUS_OK
) {
2462 BT_LOGW("Cannot add colander sink component to graph: "
2463 "graph-addr=%p, name=\"%s\", graph-status=%s",
2464 iterator
->graph
, colander_comp_name
,
2465 bt_graph_status_string(graph_status
));
2470 * Connect provided output port to the colander component's
2473 colander_in_port
= bt_component_sink_get_input_port_by_index(
2474 iterator
->colander
, 0);
2475 BT_ASSERT(colander_in_port
);
2476 graph_status
= bt_graph_connect_ports(iterator
->graph
,
2477 output_port
, colander_in_port
, NULL
);
2478 if (graph_status
!= BT_GRAPH_STATUS_OK
) {
2479 BT_LOGW("Cannot add colander sink component to graph: "
2480 "graph-addr=%p, name=\"%s\", graph-status=%s",
2481 iterator
->graph
, colander_comp_name
,
2482 bt_graph_status_string(graph_status
));
2487 * At this point everything went fine. Make the graph
2488 * nonconsumable forever so that only this notification iterator
2489 * can consume (thanks to bt_graph_consume_sink_no_check()).
2490 * This avoids leaking the notification created by the colander
2491 * sink and moved to the base notification iterator's current
2492 * notification member.
2494 bt_graph_set_can_consume(iterator
->graph
, BT_FALSE
);
2498 if (iterator
&& iterator
->graph
&& iterator
->colander
) {
2501 /* Remove created colander component from graph if any */
2502 colander_comp
= iterator
->colander
;
2503 BT_PUT(iterator
->colander
);
2506 * At this point the colander component's reference
2507 * count is 0 because iterator->colander was the only
2508 * owner. We also know that it is not connected because
2509 * this is the last operation before this function
2512 * Since we honor the preconditions here,
2513 * bt_graph_remove_unconnected_component() always
2516 ret
= bt_graph_remove_unconnected_component(iterator
->graph
,
2518 BT_ASSERT(ret
== 0);
2524 bt_put(colander_in_port
);
2525 bt_put(colander_comp_cls
);
2526 bt_put(output_port_comp
);
2528 return (void *) iterator
;
2531 struct bt_notification_iterator
*
2532 bt_private_connection_notification_iterator_from_private(
2533 struct bt_private_connection_private_notification_iterator
*private_notification_iterator
)
2536 bt_private_connection_notification_iterator_borrow_from_private(
2537 private_notification_iterator
));