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>
64 struct discarded_elements_state
{
65 struct bt_clock_value
*cur_begin
;
70 struct bt_stream
*stream
; /* owned by this */
71 struct bt_packet
*cur_packet
; /* owned by this */
72 struct discarded_elements_state discarded_packets_state
;
73 struct discarded_elements_state discarded_events_state
;
78 ACTION_TYPE_PUSH_NOTIF
,
79 ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
80 ACTION_TYPE_ADD_STREAM_STATE
,
81 ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
82 ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
83 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
,
84 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
,
88 enum action_type type
;
90 /* ACTION_TYPE_PUSH_NOTIF */
92 struct bt_notification
*notif
; /* owned by this */
95 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
97 struct bt_stream
*stream
; /* owned by this */
98 struct bt_component
*component
; /* owned by this */
99 struct bt_port
*port
; /* owned by this */
100 } map_port_to_comp_in_stream
;
102 /* ACTION_TYPE_ADD_STREAM_STATE */
104 struct bt_stream
*stream
; /* owned by this */
105 struct stream_state
*stream_state
; /* owned by this */
108 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
110 struct stream_state
*stream_state
; /* weak */
111 } set_stream_state_is_ended
;
113 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
115 struct stream_state
*stream_state
; /* weak */
116 struct bt_packet
*packet
; /* owned by this */
117 } set_stream_state_cur_packet
;
119 /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS */
120 /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS */
122 struct stream_state
*stream_state
; /* weak */
123 struct bt_clock_value
*cur_begin
; /* owned by this */
125 } update_stream_state_discarded_elements
;
130 void stream_destroy_listener(struct bt_stream
*stream
, void *data
)
132 struct bt_notification_iterator_private_connection
*iterator
= data
;
134 /* Remove associated stream state */
135 g_hash_table_remove(iterator
->stream_states
, stream
);
139 void destroy_stream_state(struct stream_state
*stream_state
)
145 BT_LOGV("Destroying stream state: stream-state-addr=%p", stream_state
);
146 BT_LOGV_STR("Putting stream state's current packet.");
147 bt_put(stream_state
->cur_packet
);
148 BT_LOGV_STR("Putting stream state's stream.");
149 bt_put(stream_state
->stream
);
150 bt_put(stream_state
->discarded_packets_state
.cur_begin
);
151 bt_put(stream_state
->discarded_events_state
.cur_begin
);
152 g_free(stream_state
);
156 void destroy_action(struct action
*action
)
160 switch (action
->type
) {
161 case ACTION_TYPE_PUSH_NOTIF
:
162 BT_PUT(action
->payload
.push_notif
.notif
);
164 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
165 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.stream
);
166 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.component
);
167 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.port
);
169 case ACTION_TYPE_ADD_STREAM_STATE
:
170 BT_PUT(action
->payload
.add_stream_state
.stream
);
171 destroy_stream_state(
172 action
->payload
.add_stream_state
.stream_state
);
173 action
->payload
.add_stream_state
.stream_state
= NULL
;
175 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
176 BT_PUT(action
->payload
.set_stream_state_cur_packet
.packet
);
178 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
180 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
:
181 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
:
182 BT_PUT(action
->payload
.update_stream_state_discarded_elements
.cur_begin
);
185 BT_LOGF("Unexpected action's type: type=%d", action
->type
);
191 void add_action(struct bt_notification_iterator_private_connection
*iterator
,
192 struct action
*action
)
194 g_array_append_val(iterator
->actions
, *action
);
198 void clear_actions(struct bt_notification_iterator_private_connection
*iterator
)
202 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
203 struct action
*action
= &g_array_index(iterator
->actions
,
206 destroy_action(action
);
209 g_array_set_size(iterator
->actions
, 0);
213 const char *action_type_string(enum action_type type
)
216 case ACTION_TYPE_PUSH_NOTIF
:
217 return "ACTION_TYPE_PUSH_NOTIF";
218 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
219 return "ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM";
220 case ACTION_TYPE_ADD_STREAM_STATE
:
221 return "ACTION_TYPE_ADD_STREAM_STATE";
222 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
223 return "ACTION_TYPE_SET_STREAM_STATE_IS_ENDED";
224 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
225 return "ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET";
226 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
:
227 return "ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS";
228 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
:
229 return "ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS";
236 void apply_actions(struct bt_notification_iterator_private_connection
*iterator
)
240 BT_LOGV("Applying notification's iterator current actions: "
241 "count=%u", iterator
->actions
->len
);
243 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
244 struct action
*action
= &g_array_index(iterator
->actions
,
247 BT_LOGV("Applying action: index=%zu, type=%s",
248 i
, action_type_string(action
->type
));
250 switch (action
->type
) {
251 case ACTION_TYPE_PUSH_NOTIF
:
252 /* Move notification to queue */
253 g_queue_push_head(iterator
->queue
,
254 action
->payload
.push_notif
.notif
);
255 bt_notification_freeze(
256 action
->payload
.push_notif
.notif
);
257 action
->payload
.push_notif
.notif
= NULL
;
259 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
260 bt_stream_map_component_to_port(
261 action
->payload
.map_port_to_comp_in_stream
.stream
,
262 action
->payload
.map_port_to_comp_in_stream
.component
,
263 action
->payload
.map_port_to_comp_in_stream
.port
);
265 case ACTION_TYPE_ADD_STREAM_STATE
:
266 /* Move stream state to hash table */
267 g_hash_table_insert(iterator
->stream_states
,
268 action
->payload
.add_stream_state
.stream
,
269 action
->payload
.add_stream_state
.stream_state
);
271 action
->payload
.add_stream_state
.stream_state
= NULL
;
273 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
275 * We know that this stream is ended. We need to
276 * remember this as long as the stream exists to
277 * enforce that the same stream does not end
280 * Here we add a destroy listener to the stream
281 * which we put after (becomes weak as the hash
282 * table key). If we were the last object to own
283 * this stream, the destroy listener is called
284 * when we call bt_put() which removes this
285 * stream state completely. This is important
286 * because the memory used by this stream object
287 * could be reused for another stream, and they
288 * must have different states.
290 bt_stream_add_destroy_listener(
291 action
->payload
.set_stream_state_is_ended
.stream_state
->stream
,
292 stream_destroy_listener
, iterator
);
293 action
->payload
.set_stream_state_is_ended
.stream_state
->is_ended
= BT_TRUE
;
294 BT_PUT(action
->payload
.set_stream_state_is_ended
.stream_state
->stream
);
296 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
297 /* Move packet to stream state's current packet */
298 BT_MOVE(action
->payload
.set_stream_state_cur_packet
.stream_state
->cur_packet
,
299 action
->payload
.set_stream_state_cur_packet
.packet
);
301 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
:
302 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
:
304 struct discarded_elements_state
*state
;
306 if (action
->type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
) {
307 state
= &action
->payload
.update_stream_state_discarded_elements
.stream_state
->discarded_packets_state
;
309 state
= &action
->payload
.update_stream_state_discarded_elements
.stream_state
->discarded_events_state
;
312 BT_MOVE(state
->cur_begin
,
313 action
->payload
.update_stream_state_discarded_elements
.cur_begin
);
314 state
->cur_count
= action
->payload
.update_stream_state_discarded_elements
.cur_count
;
318 BT_LOGF("Unexpected action's type: type=%d",
324 clear_actions(iterator
);
328 struct stream_state
*create_stream_state(struct bt_stream
*stream
)
330 struct stream_state
*stream_state
= g_new0(struct stream_state
, 1);
333 BT_LOGE_STR("Failed to allocate one stream state.");
338 * The packet index is a monotonic counter which may not start
339 * at 0 at the beginning of the stream. We therefore need to
340 * have an internal object initial state of -1ULL to distinguish
341 * between initial state and having seen a packet with
344 stream_state
->discarded_packets_state
.cur_count
= -1ULL;
347 * We keep a reference to the stream until we know it's ended
348 * because we need to be able to create an automatic "stream
349 * end" notification when the user's "next" method returns
350 * BT_NOTIFICATION_ITERATOR_STATUS_END.
352 * We put this reference when the stream is marked as ended.
354 stream_state
->stream
= bt_get(stream
);
355 BT_LOGV("Created stream state: stream-addr=%p, stream-name=\"%s\", "
356 "stream-state-addr=%p",
357 stream
, bt_stream_get_name(stream
), stream_state
);
364 void destroy_base_notification_iterator(struct bt_object
*obj
)
366 struct bt_notification_iterator
*iterator
=
367 container_of(obj
, struct bt_notification_iterator
, base
);
369 BT_LOGD_STR("Putting current notification.");
370 bt_put(iterator
->current_notification
);
375 void bt_private_connection_notification_iterator_destroy(struct bt_object
*obj
)
377 struct bt_notification_iterator_private_connection
*iterator
;
382 * The notification iterator's reference count is 0 if we're
383 * here. Increment it to avoid a double-destroy (possibly
384 * infinitely recursive). This could happen for example if the
385 * notification iterator's finalization function does bt_get()
386 * (or anything that causes bt_get() to be called) on itself
387 * (ref. count goes from 0 to 1), and then bt_put(): the
388 * reference count would go from 1 to 0 again and this function
389 * would be called again.
391 obj
->ref_count
.count
++;
392 iterator
= (void *) container_of(obj
, struct bt_notification_iterator
, base
);
393 BT_LOGD("Destroying private connection notification iterator object: addr=%p",
395 bt_private_connection_notification_iterator_finalize(iterator
);
397 if (iterator
->queue
) {
398 struct bt_notification
*notif
;
400 BT_LOGD("Putting notifications in queue.");
402 while ((notif
= g_queue_pop_tail(iterator
->queue
))) {
406 g_queue_free(iterator
->queue
);
409 if (iterator
->stream_states
) {
411 * Remove our destroy listener from each stream which
412 * has a state in this iterator. Otherwise the destroy
413 * listener would be called with an invalid/other
414 * notification iterator object.
416 GHashTableIter ht_iter
;
417 gpointer stream_gptr
, stream_state_gptr
;
419 g_hash_table_iter_init(&ht_iter
, iterator
->stream_states
);
421 while (g_hash_table_iter_next(&ht_iter
, &stream_gptr
, &stream_state_gptr
)) {
424 BT_LOGD_STR("Removing stream's destroy listener for notification iterator.");
425 bt_stream_remove_destroy_listener(
426 (void *) stream_gptr
, stream_destroy_listener
,
430 g_hash_table_destroy(iterator
->stream_states
);
433 if (iterator
->actions
) {
434 g_array_free(iterator
->actions
, TRUE
);
437 if (iterator
->connection
) {
439 * Remove ourself from the originating connection so
440 * that it does not try to finalize a dangling pointer
443 bt_connection_remove_iterator(iterator
->connection
, iterator
);
446 destroy_base_notification_iterator(obj
);
450 void bt_private_connection_notification_iterator_finalize(
451 struct bt_notification_iterator_private_connection
*iterator
)
453 struct bt_component_class
*comp_class
= NULL
;
454 bt_component_class_notification_iterator_finalize_method
455 finalize_method
= NULL
;
459 switch (iterator
->state
) {
460 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_NON_INITIALIZED
:
461 /* Skip user finalization if user initialization failed */
462 BT_LOGD("Not finalizing non-initialized notification iterator: "
463 "addr=%p", iterator
);
465 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
466 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
467 /* Already finalized */
468 BT_LOGD("Not finalizing notification iterator: already finalized: "
469 "addr=%p", iterator
);
475 BT_LOGD("Finalizing notification iterator: addr=%p", iterator
);
477 if (iterator
->state
== BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ENDED
) {
478 BT_LOGD("Updating notification iterator's state: "
479 "new-state=BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED");
480 iterator
->state
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
;
482 BT_LOGD("Updating notification iterator's state: "
483 "new-state=BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED");
484 iterator
->state
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED
;
487 assert(iterator
->upstream_component
);
488 comp_class
= iterator
->upstream_component
->class;
490 /* Call user-defined destroy method */
491 switch (comp_class
->type
) {
492 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
494 struct bt_component_class_source
*source_class
;
496 source_class
= container_of(comp_class
, struct bt_component_class_source
, parent
);
497 finalize_method
= source_class
->methods
.iterator
.finalize
;
500 case BT_COMPONENT_CLASS_TYPE_FILTER
:
502 struct bt_component_class_filter
*filter_class
;
504 filter_class
= container_of(comp_class
, struct bt_component_class_filter
, parent
);
505 finalize_method
= filter_class
->methods
.iterator
.finalize
;
513 if (finalize_method
) {
514 BT_LOGD("Calling user's finalization method: addr=%p",
517 bt_private_connection_private_notification_iterator_from_notification_iterator(iterator
));
520 iterator
->upstream_component
= NULL
;
521 iterator
->upstream_port
= NULL
;
522 BT_LOGD("Finalized notification iterator: addr=%p", iterator
);
526 void bt_private_connection_notification_iterator_set_connection(
527 struct bt_notification_iterator_private_connection
*iterator
,
528 struct bt_connection
*connection
)
531 iterator
->connection
= connection
;
532 BT_LOGV("Set notification iterator's connection: "
533 "iter-addr=%p, conn-addr=%p", iterator
, connection
);
537 int create_subscription_mask_from_notification_types(
538 struct bt_notification_iterator_private_connection
*iterator
,
539 const enum bt_notification_type
*notif_types
)
541 const enum bt_notification_type
*notif_type
;
545 iterator
->subscription_mask
= 0;
547 for (notif_type
= notif_types
;
548 *notif_type
!= BT_NOTIFICATION_TYPE_SENTINEL
;
550 switch (*notif_type
) {
551 case BT_NOTIFICATION_TYPE_ALL
:
552 iterator
->subscription_mask
|=
553 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
|
554 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
|
555 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
|
556 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
|
557 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
|
558 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
|
559 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS
|
560 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS
;
562 case BT_NOTIFICATION_TYPE_EVENT
:
563 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
565 case BT_NOTIFICATION_TYPE_INACTIVITY
:
566 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
568 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
569 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
571 case BT_NOTIFICATION_TYPE_STREAM_END
:
572 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
574 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
575 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
577 case BT_NOTIFICATION_TYPE_PACKET_END
:
578 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
580 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
581 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS
;
583 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
584 iterator
->subscription_mask
|= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS
;
591 BT_LOGV("Added notification type to subscription mask: "
593 bt_notification_type_string(*notif_type
),
594 iterator
->subscription_mask
);
602 void init_notification_iterator(struct bt_notification_iterator
*iterator
,
603 enum bt_notification_iterator_type type
,
604 bt_object_release_func destroy
)
606 bt_object_init(iterator
, destroy
);
607 iterator
->type
= type
;
611 enum bt_connection_status
bt_private_connection_notification_iterator_create(
612 struct bt_component
*upstream_comp
,
613 struct bt_port
*upstream_port
,
614 const enum bt_notification_type
*notification_types
,
615 struct bt_connection
*connection
,
616 struct bt_notification_iterator_private_connection
**user_iterator
)
618 enum bt_connection_status status
= BT_CONNECTION_STATUS_OK
;
619 enum bt_component_class_type type
;
620 struct bt_notification_iterator_private_connection
*iterator
= NULL
;
622 assert(upstream_comp
);
623 assert(upstream_port
);
624 assert(notification_types
);
625 assert(bt_port_is_connected(upstream_port
));
626 assert(user_iterator
);
627 BT_LOGD("Creating notification iterator on private connection: "
628 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
629 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
631 upstream_comp
, bt_component_get_name(upstream_comp
),
632 upstream_port
, bt_port_get_name(upstream_port
),
634 type
= bt_component_get_class_type(upstream_comp
);
635 assert(type
== BT_COMPONENT_CLASS_TYPE_SOURCE
||
636 type
== BT_COMPONENT_CLASS_TYPE_FILTER
);
637 iterator
= g_new0(struct bt_notification_iterator_private_connection
, 1);
639 BT_LOGE_STR("Failed to allocate one private connection notification iterator.");
640 status
= BT_CONNECTION_STATUS_NOMEM
;
644 init_notification_iterator((void *) iterator
,
645 BT_NOTIFICATION_ITERATOR_TYPE_PRIVATE_CONNECTION
,
646 bt_private_connection_notification_iterator_destroy
);
648 if (create_subscription_mask_from_notification_types(iterator
,
649 notification_types
)) {
650 BT_LOGW_STR("Cannot create subscription mask from notification types.");
651 status
= BT_CONNECTION_STATUS_INVALID
;
655 iterator
->stream_states
= g_hash_table_new_full(g_direct_hash
,
656 g_direct_equal
, NULL
, (GDestroyNotify
) destroy_stream_state
);
657 if (!iterator
->stream_states
) {
658 BT_LOGE_STR("Failed to allocate a GHashTable.");
659 status
= BT_CONNECTION_STATUS_NOMEM
;
663 iterator
->queue
= g_queue_new();
664 if (!iterator
->queue
) {
665 BT_LOGE_STR("Failed to allocate a GQueue.");
666 status
= BT_CONNECTION_STATUS_NOMEM
;
670 iterator
->actions
= g_array_new(FALSE
, FALSE
, sizeof(struct action
));
671 if (!iterator
->actions
) {
672 BT_LOGE_STR("Failed to allocate a GArray.");
673 status
= BT_CONNECTION_STATUS_NOMEM
;
677 iterator
->upstream_component
= upstream_comp
;
678 iterator
->upstream_port
= upstream_port
;
679 iterator
->connection
= connection
;
680 iterator
->state
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_NON_INITIALIZED
;
681 BT_LOGD("Created notification iterator: "
682 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
683 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
684 "conn-addr=%p, iter-addr=%p",
685 upstream_comp
, bt_component_get_name(upstream_comp
),
686 upstream_port
, bt_port_get_name(upstream_port
),
687 connection
, iterator
);
689 /* Move reference to user */
690 *user_iterator
= iterator
;
698 void *bt_private_connection_private_notification_iterator_get_user_data(
699 struct bt_private_connection_private_notification_iterator
*private_iterator
)
701 struct bt_notification_iterator_private_connection
*iterator
=
702 bt_private_connection_notification_iterator_borrow_from_private(private_iterator
);
704 return iterator
? iterator
->user_data
: NULL
;
707 enum bt_notification_iterator_status
708 bt_private_connection_private_notification_iterator_set_user_data(
709 struct bt_private_connection_private_notification_iterator
*private_iterator
,
712 enum bt_notification_iterator_status ret
=
713 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
714 struct bt_notification_iterator_private_connection
*iterator
=
715 bt_private_connection_notification_iterator_borrow_from_private(private_iterator
);
718 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
719 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
723 iterator
->user_data
= data
;
724 BT_LOGV("Set notification iterator's user data: "
725 "iter-addr=%p, user-data-addr=%p", iterator
, data
);
731 struct bt_notification
*bt_notification_iterator_get_notification(
732 struct bt_notification_iterator
*iterator
)
734 struct bt_notification
*notification
= NULL
;
737 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
741 notification
= bt_get(
742 bt_notification_iterator_borrow_current_notification(iterator
));
749 enum bt_private_connection_notification_iterator_notif_type
750 bt_notification_iterator_notif_type_from_notif_type(
751 enum bt_notification_type notif_type
)
753 enum bt_private_connection_notification_iterator_notif_type iter_notif_type
;
755 switch (notif_type
) {
756 case BT_NOTIFICATION_TYPE_EVENT
:
757 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
759 case BT_NOTIFICATION_TYPE_INACTIVITY
:
760 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
762 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
763 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
765 case BT_NOTIFICATION_TYPE_STREAM_END
:
766 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
768 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
769 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
771 case BT_NOTIFICATION_TYPE_PACKET_END
:
772 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
774 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
775 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS
;
777 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
778 iter_notif_type
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS
;
784 return iter_notif_type
;
788 bt_bool
validate_notification(
789 struct bt_notification_iterator_private_connection
*iterator
,
790 struct bt_notification
*notif
,
791 struct bt_stream
*notif_stream
,
792 struct bt_packet
*notif_packet
)
794 bt_bool is_valid
= BT_TRUE
;
795 struct stream_state
*stream_state
;
796 struct bt_port
*stream_comp_cur_port
;
798 assert(notif_stream
);
799 stream_comp_cur_port
=
800 bt_stream_port_for_component(notif_stream
,
801 iterator
->upstream_component
);
802 if (!stream_comp_cur_port
) {
804 * This is the first time this notification iterator
805 * bumps into this stream. Add an action to map the
806 * iterator's upstream component to the iterator's
807 * upstream port in this stream.
809 struct action action
= {
810 .type
= ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
811 .payload
.map_port_to_comp_in_stream
= {
812 .stream
= bt_get(notif_stream
),
813 .component
= bt_get(iterator
->upstream_component
),
814 .port
= bt_get(iterator
->upstream_port
),
818 add_action(iterator
, &action
);
820 if (stream_comp_cur_port
!= iterator
->upstream_port
) {
822 * It looks like two different ports of the same
823 * component are emitting notifications which
824 * have references to the same stream. This is
825 * bad: the API guarantees that it can never
828 BT_LOGW("Two different ports of the same component are emitting notifications which refer to the same stream: "
829 "stream-addr=%p, stream-name=\"%s\", "
830 "stream-comp-cur-port-addr=%p, "
831 "stream-comp-cur-port-name=%p, "
832 "iter-upstream-port-addr=%p, "
833 "iter-upstream-port-name=%s",
835 bt_stream_get_name(notif_stream
),
836 stream_comp_cur_port
,
837 bt_port_get_name(stream_comp_cur_port
),
838 iterator
->upstream_port
,
839 bt_port_get_name(iterator
->upstream_port
));
846 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
849 BT_LOGV("Stream state already exists: "
850 "stream-addr=%p, stream-name=\"%s\", "
851 "stream-state-addr=%p",
853 bt_stream_get_name(notif_stream
), stream_state
);
855 if (stream_state
->is_ended
) {
857 * There's a new notification which has a
858 * reference to a stream which, from this
859 * iterator's point of view, is ended ("end of
860 * stream" notification was returned). This is
861 * bad: the API guarantees that it can never
864 BT_LOGW("Stream is already ended: "
865 "stream-addr=%p, stream-name=\"%s\"",
867 bt_stream_get_name(notif_stream
));
872 switch (notif
->type
) {
873 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
875 * We already have a stream state, which means
876 * we already returned a "stream begin"
877 * notification: this is an invalid duplicate.
879 BT_LOGW("Duplicate stream beginning notification: "
880 "stream-addr=%p, stream-name=\"%s\"",
882 bt_stream_get_name(notif_stream
));
885 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
886 if (notif_packet
== stream_state
->cur_packet
) {
887 /* Duplicate "packet begin" notification */
888 BT_LOGW("Duplicate stream beginning notification: "
889 "stream-addr=%p, stream-name=\"%s\", "
892 bt_stream_get_name(notif_stream
),
908 bt_bool
is_subscribed_to_notification_type(
909 struct bt_notification_iterator_private_connection
*iterator
,
910 enum bt_notification_type notif_type
)
912 uint32_t iter_notif_type
=
913 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
916 return (iter_notif_type
& iterator
->subscription_mask
) ? BT_TRUE
: BT_FALSE
;
920 void add_action_push_notif(
921 struct bt_notification_iterator_private_connection
*iterator
,
922 struct bt_notification
*notif
)
924 struct action action
= {
925 .type
= ACTION_TYPE_PUSH_NOTIF
,
930 if (!is_subscribed_to_notification_type(iterator
, notif
->type
)) {
934 action
.payload
.push_notif
.notif
= bt_get(notif
);
935 add_action(iterator
, &action
);
936 BT_LOGV("Added \"push notification\" action: notif-addr=%p", notif
);
940 int add_action_push_notif_stream_begin(
941 struct bt_notification_iterator_private_connection
*iterator
,
942 struct bt_stream
*stream
)
945 struct bt_notification
*stream_begin_notif
= NULL
;
947 if (!is_subscribed_to_notification_type(iterator
,
948 BT_NOTIFICATION_TYPE_STREAM_BEGIN
)) {
949 BT_LOGV("Not adding \"push stream beginning notification\" action: "
950 "notification iterator is not subscribed: addr=%p",
956 stream_begin_notif
= bt_notification_stream_begin_create(stream
);
957 if (!stream_begin_notif
) {
958 BT_LOGE_STR("Cannot create stream beginning notification.");
962 add_action_push_notif(iterator
, stream_begin_notif
);
963 BT_LOGV("Added \"push stream beginning notification\" action: "
964 "stream-addr=%p, stream-name=\"%s\"",
965 stream
, bt_stream_get_name(stream
));
972 bt_put(stream_begin_notif
);
977 int add_action_push_notif_stream_end(
978 struct bt_notification_iterator_private_connection
*iterator
,
979 struct bt_stream
*stream
)
982 struct bt_notification
*stream_end_notif
= NULL
;
984 if (!is_subscribed_to_notification_type(iterator
,
985 BT_NOTIFICATION_TYPE_STREAM_END
)) {
986 BT_LOGV("Not adding \"push stream end notification\" action: "
987 "notification iterator is not subscribed: addr=%p",
993 stream_end_notif
= bt_notification_stream_end_create(stream
);
994 if (!stream_end_notif
) {
995 BT_LOGE_STR("Cannot create stream end notification.");
999 add_action_push_notif(iterator
, stream_end_notif
);
1000 BT_LOGV("Added \"push stream end notification\" action: "
1001 "stream-addr=%p, stream-name=\"%s\"",
1002 stream
, bt_stream_get_name(stream
));
1009 bt_put(stream_end_notif
);
1014 int add_action_push_notif_packet_begin(
1015 struct bt_notification_iterator_private_connection
*iterator
,
1016 struct bt_packet
*packet
)
1019 struct bt_notification
*packet_begin_notif
= NULL
;
1021 if (!is_subscribed_to_notification_type(iterator
,
1022 BT_NOTIFICATION_TYPE_PACKET_BEGIN
)) {
1023 BT_LOGV("Not adding \"push packet beginning notification\" action: "
1024 "notification iterator is not subscribed: addr=%p",
1030 packet_begin_notif
= bt_notification_packet_begin_create(packet
);
1031 if (!packet_begin_notif
) {
1032 BT_LOGE_STR("Cannot create packet beginning notification.");
1036 add_action_push_notif(iterator
, packet_begin_notif
);
1037 BT_LOGV("Added \"push packet beginning notification\" action: "
1038 "packet-addr=%p", packet
);
1045 bt_put(packet_begin_notif
);
1050 int add_action_push_notif_packet_end(
1051 struct bt_notification_iterator_private_connection
*iterator
,
1052 struct bt_packet
*packet
)
1055 struct bt_notification
*packet_end_notif
= NULL
;
1057 if (!is_subscribed_to_notification_type(iterator
,
1058 BT_NOTIFICATION_TYPE_PACKET_END
)) {
1059 BT_LOGV("Not adding \"push packet end notification\" action: "
1060 "notification iterator is not subscribed: addr=%p",
1066 packet_end_notif
= bt_notification_packet_end_create(packet
);
1067 if (!packet_end_notif
) {
1068 BT_LOGE_STR("Cannot create packet end notification.");
1072 add_action_push_notif(iterator
, packet_end_notif
);
1073 BT_LOGV("Added \"push packet end notification\" action: "
1074 "packet-addr=%p", packet
);
1081 bt_put(packet_end_notif
);
1086 void add_action_set_stream_state_is_ended(
1087 struct bt_notification_iterator_private_connection
*iterator
,
1088 struct stream_state
*stream_state
)
1090 struct action action
= {
1091 .type
= ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
1092 .payload
.set_stream_state_is_ended
= {
1093 .stream_state
= stream_state
,
1097 assert(stream_state
);
1098 add_action(iterator
, &action
);
1099 BT_LOGV("Added \"set stream state's ended\" action: "
1100 "stream-state-addr=%p", stream_state
);
1104 void add_action_set_stream_state_cur_packet(
1105 struct bt_notification_iterator_private_connection
*iterator
,
1106 struct stream_state
*stream_state
,
1107 struct bt_packet
*packet
)
1109 struct action action
= {
1110 .type
= ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
1111 .payload
.set_stream_state_cur_packet
= {
1112 .stream_state
= stream_state
,
1113 .packet
= bt_get(packet
),
1117 assert(stream_state
);
1118 add_action(iterator
, &action
);
1119 BT_LOGV("Added \"set stream state's current packet\" action: "
1120 "stream-state-addr=%p, packet-addr=%p",
1121 stream_state
, packet
);
1125 void add_action_update_stream_state_discarded_elements(
1126 struct bt_notification_iterator_private_connection
*iterator
,
1127 enum action_type type
,
1128 struct stream_state
*stream_state
,
1129 struct bt_clock_value
*cur_begin
,
1132 struct action action
= {
1134 .payload
.update_stream_state_discarded_elements
= {
1135 .stream_state
= stream_state
,
1136 .cur_begin
= bt_get(cur_begin
),
1137 .cur_count
= cur_count
,
1141 assert(stream_state
);
1142 assert(type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
||
1143 type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
);
1144 add_action(iterator
, &action
);
1145 if (type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
) {
1146 BT_LOGV("Added \"update stream state's discarded packets\" action: "
1147 "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64
,
1148 stream_state
, cur_begin
, cur_count
);
1149 } else if (type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
) {
1150 BT_LOGV("Added \"update stream state's discarded events\" action: "
1151 "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64
,
1152 stream_state
, cur_begin
, cur_count
);
1157 int ensure_stream_state_exists(
1158 struct bt_notification_iterator_private_connection
*iterator
,
1159 struct bt_notification
*stream_begin_notif
,
1160 struct bt_stream
*notif_stream
,
1161 struct stream_state
**_stream_state
)
1164 struct stream_state
*stream_state
= NULL
;
1166 if (!notif_stream
) {
1168 * The notification does not reference any stream: no
1169 * need to get or create a stream state.
1174 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
1176 if (!stream_state
) {
1178 * This iterator did not bump into this stream yet:
1179 * create a stream state and a "stream begin"
1182 struct action action
= {
1183 .type
= ACTION_TYPE_ADD_STREAM_STATE
,
1184 .payload
.add_stream_state
= {
1185 .stream
= bt_get(notif_stream
),
1186 .stream_state
= NULL
,
1190 stream_state
= create_stream_state(notif_stream
);
1191 if (!stream_state
) {
1192 BT_LOGE_STR("Cannot create stream state.");
1196 action
.payload
.add_stream_state
.stream_state
= stream_state
;
1197 add_action(iterator
, &action
);
1199 if (stream_begin_notif
) {
1200 add_action_push_notif(iterator
, stream_begin_notif
);
1202 ret
= add_action_push_notif_stream_begin(iterator
,
1205 BT_LOGE_STR("Cannot add \"push stream beginning notification\" action.");
1213 destroy_stream_state(stream_state
);
1214 stream_state
= NULL
;
1218 *_stream_state
= stream_state
;
1223 struct bt_field
*get_struct_field_uint(struct bt_field
*struct_field
,
1224 const char *field_name
)
1226 struct bt_field
*field
= NULL
;
1227 struct bt_field_type
*ft
= NULL
;
1229 field
= bt_field_structure_get_field_by_name(struct_field
,
1232 BT_LOGV_STR("`%s` field does not exist.");
1236 if (!bt_field_is_integer(field
)) {
1237 BT_LOGV("Skipping `%s` field because its type is not an integer field type: "
1238 "field-addr=%p, ft-addr=%p, ft-id=%s", field_name
,
1239 field
, ft
, bt_field_type_id_string(
1240 bt_field_type_get_type_id(ft
)));
1245 ft
= bt_field_get_type(field
);
1248 if (bt_field_type_integer_is_signed(ft
)) {
1249 BT_LOGV("Skipping `%s` integer field because its type is signed: "
1250 "field-addr=%p, ft-addr=%p", field_name
, field
, ft
);
1261 uint64_t get_packet_context_events_discarded(struct bt_packet
*packet
)
1263 struct bt_field
*packet_context
= NULL
;
1264 struct bt_field
*field
= NULL
;
1265 uint64_t retval
= -1ULL;
1268 packet_context
= bt_packet_get_context(packet
);
1269 if (!packet_context
) {
1273 field
= get_struct_field_uint(packet_context
, "events_discarded");
1275 BT_LOGV("`events_discarded` field does not exist in packet's context field: "
1276 "packet-addr=%p, packet-context-field-addr=%p",
1277 packet
, packet_context
);
1281 assert(bt_field_is_integer(field
));
1282 ret
= bt_field_unsigned_integer_get_value(field
, &retval
);
1284 BT_LOGV("Cannot get raw value of packet's context field's `events_discarded` integer field: "
1285 "packet-addr=%p, field-addr=%p",
1292 bt_put(packet_context
);
1298 uint64_t get_packet_context_packet_seq_num(struct bt_packet
*packet
)
1300 struct bt_field
*packet_context
= NULL
;
1301 struct bt_field
*field
= NULL
;
1302 uint64_t retval
= -1ULL;
1305 packet_context
= bt_packet_get_context(packet
);
1306 if (!packet_context
) {
1310 field
= get_struct_field_uint(packet_context
, "packet_seq_num");
1312 BT_LOGV("`packet_seq_num` field does not exist in packet's context field: "
1313 "packet-addr=%p, packet-context-field-addr=%p",
1314 packet
, packet_context
);
1318 assert(bt_field_is_integer(field
));
1319 ret
= bt_field_unsigned_integer_get_value(field
, &retval
);
1321 BT_LOGV("Cannot get raw value of packet's context field's `packet_seq_num` integer field: "
1322 "packet-addr=%p, field-addr=%p",
1329 bt_put(packet_context
);
1335 int handle_discarded_packets(
1336 struct bt_notification_iterator_private_connection
*iterator
,
1337 struct bt_packet
*packet
,
1338 struct bt_clock_value
*ts_begin
,
1339 struct bt_clock_value
*ts_end
,
1340 struct stream_state
*stream_state
)
1342 struct bt_notification
*notif
= NULL
;
1344 uint64_t prev_count
, next_count
;
1347 next_count
= get_packet_context_packet_seq_num(packet
);
1348 if (next_count
== -1ULL) {
1350 * Stream does not have seqnum field, skip discarded
1355 prev_count
= stream_state
->discarded_packets_state
.cur_count
;
1357 if (prev_count
!= -1ULL) {
1358 if (next_count
< prev_count
) {
1359 BT_LOGW("Current value of packet's context field's `packet_seq_num` field is lesser than the previous value for the same stream: "
1360 "not updating the stream state's current value: "
1361 "packet-addr=%p, prev-count=%" PRIu64
", "
1362 "cur-count=%" PRIu64
,
1363 packet
, prev_count
, next_count
);
1366 if (next_count
== prev_count
) {
1367 BT_LOGW("Current value of packet's context field's `packet_seq_num` field is equal to the previous value for the same stream: "
1368 "not updating the stream state's current value: "
1369 "packet-addr=%p, prev-count=%" PRIu64
", "
1370 "cur-count=%" PRIu64
,
1371 packet
, prev_count
, next_count
);
1375 diff
= next_count
- prev_count
;
1378 * Add a discarded packets notification. The packets
1379 * are considered to be lost between the state's last time
1380 * and the current packet's beginning time.
1381 * The counter is expected to monotonically increase of
1382 * 1 for each packet. Therefore, the number of missing
1383 * packets is 'diff - 1'.
1385 notif
= bt_notification_discarded_elements_create(
1386 BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
,
1387 stream_state
->stream
,
1388 stream_state
->discarded_packets_state
.cur_begin
,
1389 ts_begin
, diff
- 1);
1391 BT_LOGE_STR("Cannot create discarded packets notification.");
1396 add_action_push_notif(iterator
, notif
);
1400 add_action_update_stream_state_discarded_elements(iterator
,
1401 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
,
1402 stream_state
, ts_end
, next_count
);
1410 int handle_discarded_events(
1411 struct bt_notification_iterator_private_connection
*iterator
,
1412 struct bt_packet
*packet
,
1413 struct bt_clock_value
*ts_begin
,
1414 struct bt_clock_value
*ts_end
,
1415 struct stream_state
*stream_state
)
1417 struct bt_notification
*notif
= NULL
;
1419 uint64_t next_count
;
1422 next_count
= get_packet_context_events_discarded(packet
);
1423 if (next_count
== -1ULL) {
1424 next_count
= stream_state
->discarded_events_state
.cur_count
;
1428 if (next_count
< stream_state
->discarded_events_state
.cur_count
) {
1429 BT_LOGW("Current value of packet's context field's `events_discarded` field is lesser than the previous value for the same stream: "
1430 "not updating the stream state's current value: "
1431 "packet-addr=%p, prev-count=%" PRIu64
", "
1432 "cur-count=%" PRIu64
,
1433 packet
, stream_state
->discarded_events_state
.cur_count
,
1438 diff
= next_count
- stream_state
->discarded_events_state
.cur_count
;
1441 * Add a discarded events notification. The events are
1442 * considered to be lost betweem the state's last time
1443 * and the current packet's end time.
1445 notif
= bt_notification_discarded_elements_create(
1446 BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
,
1447 stream_state
->stream
,
1448 stream_state
->discarded_events_state
.cur_begin
,
1451 BT_LOGE_STR("Cannot create discarded events notification.");
1456 add_action_push_notif(iterator
, notif
);
1460 add_action_update_stream_state_discarded_elements(iterator
,
1461 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
,
1462 stream_state
, ts_end
, next_count
);
1470 int get_field_clock_value(struct bt_field
*root_field
,
1471 const char *field_name
,
1472 struct bt_clock_value
**user_clock_val
)
1474 struct bt_field
*field
;
1475 struct bt_field_type
*ft
= NULL
;
1476 struct bt_clock_class
*clock_class
= NULL
;
1477 struct bt_clock_value
*clock_value
= NULL
;
1481 field
= get_struct_field_uint(root_field
, field_name
);
1483 /* Not an error: skip this */
1487 ft
= bt_field_get_type(field
);
1489 clock_class
= bt_field_type_integer_get_mapped_clock_class(ft
);
1491 BT_LOGW("Integer field type has no mapped clock class but it's expected to have one: "
1497 ret
= bt_field_unsigned_integer_get_value(field
, &val
);
1499 BT_LOGW("Cannot get integer field's raw value: "
1500 "field-addr=%p", field
);
1505 clock_value
= bt_clock_value_create(clock_class
, val
);
1507 BT_LOGE_STR("Cannot create clock value from clock class.");
1512 /* Move clock value to user */
1513 *user_clock_val
= clock_value
;
1519 bt_put(clock_class
);
1520 bt_put(clock_value
);
1525 int get_ts_begin_ts_end_from_packet(struct bt_packet
*packet
,
1526 struct bt_clock_value
**user_ts_begin
,
1527 struct bt_clock_value
**user_ts_end
)
1529 struct bt_field
*packet_context
= NULL
;
1530 struct bt_clock_value
*ts_begin
= NULL
;
1531 struct bt_clock_value
*ts_end
= NULL
;
1534 packet_context
= bt_packet_get_context(packet
);
1535 if (!packet_context
) {
1539 ret
= get_field_clock_value(packet_context
, "timestamp_begin",
1542 BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: "
1543 "packet-addr=%p, packet-context-field-addr=%p",
1544 packet
, packet_context
);
1548 ret
= get_field_clock_value(packet_context
, "timestamp_end",
1551 BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: "
1552 "packet-addr=%p, packet-context-field-addr=%p",
1553 packet
, packet_context
);
1557 /* Move clock values to user */
1558 *user_ts_begin
= ts_begin
;
1560 *user_ts_end
= ts_end
;
1564 bt_put(packet_context
);
1571 int handle_discarded_elements(
1572 struct bt_notification_iterator_private_connection
*iterator
,
1573 struct bt_packet
*packet
, struct stream_state
*stream_state
)
1575 struct bt_clock_value
*ts_begin
= NULL
;
1576 struct bt_clock_value
*ts_end
= NULL
;
1579 ret
= get_ts_begin_ts_end_from_packet(packet
, &ts_begin
, &ts_end
);
1581 BT_LOGW("Cannot get packet's beginning or end clock values: "
1582 "packet-addr=%p, ret=%d", packet
, ret
);
1587 ret
= handle_discarded_packets(iterator
, packet
, ts_begin
, ts_end
,
1590 BT_LOGW("Cannot handle discarded packets for packet: "
1591 "packet-addr=%p, ret=%d", packet
, ret
);
1596 ret
= handle_discarded_events(iterator
, packet
, ts_begin
, ts_end
,
1599 BT_LOGW("Cannot handle discarded events for packet: "
1600 "packet-addr=%p, ret=%d", packet
, ret
);
1612 int handle_packet_switch(
1613 struct bt_notification_iterator_private_connection
*iterator
,
1614 struct bt_notification
*packet_begin_notif
,
1615 struct bt_packet
*new_packet
,
1616 struct stream_state
*stream_state
)
1620 if (stream_state
->cur_packet
== new_packet
) {
1624 BT_LOGV("Handling packet switch: "
1625 "cur-packet-addr=%p, new-packet-addr=%p",
1626 stream_state
->cur_packet
, new_packet
);
1628 if (stream_state
->cur_packet
) {
1629 /* End of the current packet */
1630 ret
= add_action_push_notif_packet_end(iterator
,
1631 stream_state
->cur_packet
);
1633 BT_LOGE_STR("Cannot add \"push packet end notification\" action.");
1639 * Check the new packet's context fields for discarded packets
1640 * and events to emit those automatic notifications.
1642 ret
= handle_discarded_elements(iterator
, new_packet
, stream_state
);
1644 BT_LOGE_STR("Cannot handle discarded elements for new packet.");
1648 /* Beginning of the new packet */
1649 if (packet_begin_notif
) {
1650 add_action_push_notif(iterator
, packet_begin_notif
);
1651 } else if (new_packet
) {
1652 ret
= add_action_push_notif_packet_begin(iterator
,
1655 BT_LOGE_STR("Cannot add \"push packet beginning notification\" action.");
1660 add_action_set_stream_state_cur_packet(iterator
, stream_state
,
1672 int handle_notif_stream_begin(
1673 struct bt_notification_iterator_private_connection
*iterator
,
1674 struct bt_notification
*notif
,
1675 struct bt_stream
*notif_stream
)
1678 struct stream_state
*stream_state
;
1680 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_BEGIN
);
1681 assert(notif_stream
);
1682 ret
= ensure_stream_state_exists(iterator
, notif
, notif_stream
,
1685 BT_LOGE_STR("Cannot ensure that stream state exists.");
1699 int handle_notif_stream_end(
1700 struct bt_notification_iterator_private_connection
*iterator
,
1701 struct bt_notification
*notif
,
1702 struct bt_stream
*notif_stream
)
1705 struct stream_state
*stream_state
;
1707 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_END
);
1708 assert(notif_stream
);
1709 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1712 BT_LOGE_STR("Cannot ensure that stream state exists.");
1716 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1718 BT_LOGE_STR("Cannot handle packet switch.");
1722 add_action_push_notif(iterator
, notif
);
1723 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1734 int handle_notif_discarded_elements(
1735 struct bt_notification_iterator_private_connection
*iterator
,
1736 struct bt_notification
*notif
,
1737 struct bt_stream
*notif_stream
)
1740 struct stream_state
*stream_state
;
1742 assert(notif
->type
== BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
||
1743 notif
->type
== BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
);
1744 assert(notif_stream
);
1745 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1748 BT_LOGE_STR("Cannot ensure that stream state exists.");
1752 add_action_push_notif(iterator
, notif
);
1763 int handle_notif_packet_begin(
1764 struct bt_notification_iterator_private_connection
*iterator
,
1765 struct bt_notification
*notif
,
1766 struct bt_stream
*notif_stream
,
1767 struct bt_packet
*notif_packet
)
1770 struct stream_state
*stream_state
;
1772 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_BEGIN
);
1773 assert(notif_packet
);
1774 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1777 BT_LOGE_STR("Cannot ensure that stream state exists.");
1781 ret
= handle_packet_switch(iterator
, notif
, notif_packet
, stream_state
);
1783 BT_LOGE_STR("Cannot handle packet switch.");
1797 int handle_notif_packet_end(
1798 struct bt_notification_iterator_private_connection
*iterator
,
1799 struct bt_notification
*notif
,
1800 struct bt_stream
*notif_stream
,
1801 struct bt_packet
*notif_packet
)
1804 struct stream_state
*stream_state
;
1806 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_END
);
1807 assert(notif_packet
);
1808 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1811 BT_LOGE_STR("Cannot ensure that stream state exists.");
1815 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1817 BT_LOGE_STR("Cannot handle packet switch.");
1821 /* End of the current packet */
1822 add_action_push_notif(iterator
, notif
);
1823 add_action_set_stream_state_cur_packet(iterator
, stream_state
, NULL
);
1834 int handle_notif_event(
1835 struct bt_notification_iterator_private_connection
*iterator
,
1836 struct bt_notification
*notif
,
1837 struct bt_stream
*notif_stream
,
1838 struct bt_packet
*notif_packet
)
1841 struct stream_state
*stream_state
;
1843 assert(notif
->type
== BT_NOTIFICATION_TYPE_EVENT
);
1844 assert(notif_packet
);
1845 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1848 BT_LOGE_STR("Cannot ensure that stream state exists.");
1852 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1854 BT_LOGE_STR("Cannot handle packet switch.");
1858 add_action_push_notif(iterator
, notif
);
1869 int enqueue_notification_and_automatic(
1870 struct bt_notification_iterator_private_connection
*iterator
,
1871 struct bt_notification
*notif
)
1874 struct bt_event
*notif_event
= NULL
;
1875 struct bt_stream
*notif_stream
= NULL
;
1876 struct bt_packet
*notif_packet
= NULL
;
1880 BT_LOGV("Enqueuing user notification and automatic notifications: "
1881 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1883 // TODO: Skip most of this if the iterator is only subscribed
1884 // to event/inactivity notifications.
1886 /* Get the stream and packet referred by the notification */
1887 switch (notif
->type
) {
1888 case BT_NOTIFICATION_TYPE_EVENT
:
1889 notif_event
= bt_notification_event_borrow_event(notif
);
1890 assert(notif_event
);
1891 notif_packet
= bt_event_borrow_packet(notif_event
);
1892 assert(notif_packet
);
1894 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1896 bt_notification_stream_begin_borrow_stream(notif
);
1897 assert(notif_stream
);
1899 case BT_NOTIFICATION_TYPE_STREAM_END
:
1900 notif_stream
= bt_notification_stream_end_borrow_stream(notif
);
1901 assert(notif_stream
);
1903 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1905 bt_notification_packet_begin_borrow_packet(notif
);
1906 assert(notif_packet
);
1908 case BT_NOTIFICATION_TYPE_PACKET_END
:
1909 notif_packet
= bt_notification_packet_end_borrow_packet(notif
);
1910 assert(notif_packet
);
1912 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1917 * Invalid type of notification. Only the notification
1918 * types above are allowed to be returned by a user
1921 BT_LOGF("Unexpected notification type at this point: "
1922 "notif-addr=%p, notif-type=%s", notif
,
1923 bt_notification_type_string(notif
->type
));
1928 notif_stream
= bt_packet_borrow_stream(notif_packet
);
1929 assert(notif_stream
);
1932 if (!notif_stream
) {
1934 * The notification has no reference to a stream: it
1935 * cannot cause the creation of automatic notifications.
1937 BT_LOGV_STR("Notification has no reference to any stream: skipping automatic notification generation.");
1941 if (!validate_notification(iterator
, notif
, notif_stream
,
1943 BT_LOGW_STR("Invalid notification.");
1948 switch (notif
->type
) {
1949 case BT_NOTIFICATION_TYPE_EVENT
:
1950 ret
= handle_notif_event(iterator
, notif
, notif_stream
,
1953 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1954 ret
= handle_notif_stream_begin(iterator
, notif
, notif_stream
);
1956 case BT_NOTIFICATION_TYPE_STREAM_END
:
1957 ret
= handle_notif_stream_end(iterator
, notif
, notif_stream
);
1959 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1960 ret
= handle_notif_packet_begin(iterator
, notif
, notif_stream
,
1963 case BT_NOTIFICATION_TYPE_PACKET_END
:
1964 ret
= handle_notif_packet_end(iterator
, notif
, notif_stream
,
1967 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
1968 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
1969 ret
= handle_notif_discarded_elements(iterator
, notif
,
1972 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1973 add_action_push_notif(iterator
, notif
);
1980 BT_LOGW_STR("Failed to handle notification for automatic notification generation.");
1984 apply_actions(iterator
);
1985 BT_LOGV("Enqueued user notification and automatic notifications: "
1986 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1997 int handle_end(struct bt_notification_iterator_private_connection
*iterator
)
1999 GHashTableIter stream_state_iter
;
2000 gpointer stream_gptr
, stream_state_gptr
;
2003 BT_LOGV("Handling end of iteration: addr=%p", iterator
);
2006 * Emit a "stream end" notification for each non-ended stream
2007 * known by this iterator and mark them as ended.
2009 g_hash_table_iter_init(&stream_state_iter
, iterator
->stream_states
);
2011 while (g_hash_table_iter_next(&stream_state_iter
, &stream_gptr
,
2012 &stream_state_gptr
)) {
2013 struct stream_state
*stream_state
= stream_state_gptr
;
2015 assert(stream_state_gptr
);
2017 if (stream_state
->is_ended
) {
2021 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
2023 BT_LOGE_STR("Cannot handle packet switch.");
2027 ret
= add_action_push_notif_stream_end(iterator
, stream_gptr
);
2029 BT_LOGE_STR("Cannot add \"push stream end notification\" action.");
2033 add_action_set_stream_state_is_ended(iterator
, stream_state
);
2036 apply_actions(iterator
);
2037 BT_LOGV("Handled end of iteration: addr=%p", iterator
);
2048 enum bt_notification_iterator_status
ensure_queue_has_notifications(
2049 struct bt_notification_iterator_private_connection
*iterator
)
2051 struct bt_private_connection_private_notification_iterator
*priv_iterator
=
2052 bt_private_connection_private_notification_iterator_from_notification_iterator(iterator
);
2053 bt_component_class_notification_iterator_next_method next_method
= NULL
;
2054 struct bt_notification_iterator_next_method_return next_return
= {
2055 .status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
,
2056 .notification
= NULL
,
2058 enum bt_notification_iterator_status status
=
2059 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
2063 BT_LOGD("Ensuring that notification iterator's queue has at least one notification: "
2064 "iter-addr=%p, queue-size=%u, iter-state=%s",
2065 iterator
, iterator
->queue
->length
,
2066 bt_private_connection_notification_iterator_state_string(iterator
->state
));
2068 if (iterator
->queue
->length
> 0) {
2070 * We already have enough. Even if this notification
2071 * iterator is finalized, its user can still flush its
2072 * current queue's content by calling its "next" method
2073 * since this content is local and has no impact on what
2074 * used to be the iterator's upstream component.
2076 BT_LOGD_STR("Queue already has at least one notification.");
2080 switch (iterator
->state
) {
2081 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
2082 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
2083 BT_LOGD_STR("Notification iterator's \"next\" called, but it is finalized.");
2084 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
2086 case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ENDED
:
2087 BT_LOGD_STR("Notification iterator is ended.");
2088 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
2094 assert(iterator
->upstream_component
);
2095 assert(iterator
->upstream_component
->class);
2097 /* Pick the appropriate "next" method */
2098 switch (iterator
->upstream_component
->class->type
) {
2099 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
2101 struct bt_component_class_source
*source_class
=
2102 container_of(iterator
->upstream_component
->class,
2103 struct bt_component_class_source
, parent
);
2105 assert(source_class
->methods
.iterator
.next
);
2106 next_method
= source_class
->methods
.iterator
.next
;
2109 case BT_COMPONENT_CLASS_TYPE_FILTER
:
2111 struct bt_component_class_filter
*filter_class
=
2112 container_of(iterator
->upstream_component
->class,
2113 struct bt_component_class_filter
, parent
);
2115 assert(filter_class
->methods
.iterator
.next
);
2116 next_method
= filter_class
->methods
.iterator
.next
;
2124 * Call the user's "next" method to get the next notification
2127 assert(next_method
);
2129 while (iterator
->queue
->length
== 0) {
2130 BT_LOGD_STR("Calling user's \"next\" method.");
2131 next_return
= next_method(priv_iterator
);
2132 BT_LOGD("User method returned: status=%s",
2133 bt_notification_iterator_status_string(next_return
.status
));
2134 if (next_return
.status
< 0) {
2135 BT_LOGW_STR("User method failed.");
2136 status
= next_return
.status
;
2140 if (iterator
->state
== BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED
||
2141 iterator
->state
== BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
) {
2143 * The user's "next" method, somehow, cancelled
2144 * its own notification iterator. This can
2145 * happen, for example, when the user's method
2146 * removes the port on which there's the
2147 * connection from which the iterator was
2148 * created. In this case, said connection is
2149 * ended, and all its notification iterators are
2152 * Only bt_put() the returned notification if
2154 * BT_NOTIFICATION_ITERATOR_STATUS_OK because
2155 * otherwise this field could be garbage.
2157 if (next_return
.status
==
2158 BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
2159 bt_put(next_return
.notification
);
2162 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
2166 switch (next_return
.status
) {
2167 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
2168 ret
= handle_end(iterator
);
2170 BT_LOGW_STR("Cannot handle end of iteration.");
2171 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
2175 assert(iterator
->state
==
2176 BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ACTIVE
);
2177 iterator
->state
= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ENDED
;
2179 if (iterator
->queue
->length
== 0) {
2180 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
2183 BT_LOGD("Set new status: status=%s",
2184 bt_notification_iterator_status_string(status
));
2186 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
:
2187 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
2189 case BT_NOTIFICATION_ITERATOR_STATUS_OK
:
2190 if (!next_return
.notification
) {
2191 BT_LOGW_STR("User method returned BT_NOTIFICATION_ITERATOR_STATUS_OK, but notification is NULL.");
2192 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
2197 * Ignore some notifications which are always
2198 * automatically generated by the notification
2199 * iterator to make sure they have valid values.
2201 switch (next_return
.notification
->type
) {
2202 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
2203 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
2204 BT_LOGV("Ignoring discarded elements notification returned by notification iterator's \"next\" method: "
2206 bt_notification_type_string(next_return
.notification
->type
));
2207 BT_PUT(next_return
.notification
);
2214 * We know the notification is valid. Before we
2215 * push it to the head of the queue, push the
2216 * appropriate automatic notifications if any.
2218 ret
= enqueue_notification_and_automatic(iterator
,
2219 next_return
.notification
);
2220 BT_PUT(next_return
.notification
);
2222 BT_LOGW("Cannot enqueue notification and automatic notifications.");
2223 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
2228 /* Unknown non-error status */
2237 enum bt_notification_iterator_status
2238 bt_notification_iterator_next(struct bt_notification_iterator
*iterator
)
2240 enum bt_notification_iterator_status status
;
2243 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
2244 status
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
2248 BT_LOGD("Notification iterator's \"next\": iter-addr=%p", iterator
);
2250 switch (iterator
->type
) {
2251 case BT_NOTIFICATION_ITERATOR_TYPE_PRIVATE_CONNECTION
:
2253 struct bt_notification_iterator_private_connection
*priv_conn_iter
=
2255 struct bt_notification
*notif
;
2258 * Make sure that the iterator's queue contains at least
2261 status
= ensure_queue_has_notifications(priv_conn_iter
);
2262 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
2267 * Move the notification at the tail of the queue to the
2268 * iterator's current notification.
2270 assert(priv_conn_iter
->queue
->length
> 0);
2271 notif
= g_queue_pop_tail(priv_conn_iter
->queue
);
2272 bt_notification_iterator_replace_current_notification(
2277 case BT_NOTIFICATION_ITERATOR_TYPE_OUTPUT_PORT
:
2279 struct bt_notification_iterator_output_port
*out_port_iter
=
2283 * Keep current notification in case there's an error:
2284 * restore this notification so that the current
2285 * notification is not changed from the user's point of
2288 struct bt_notification
*old_notif
=
2289 bt_get(bt_notification_iterator_borrow_current_notification(iterator
));
2290 enum bt_graph_status graph_status
;
2293 * Put current notification since it's possibly
2294 * about to be replaced by a new one by the
2297 bt_notification_iterator_replace_current_notification(
2299 graph_status
= bt_graph_consume_sink_no_check(
2300 out_port_iter
->graph
,
2301 out_port_iter
->colander
);
2302 switch (graph_status
) {
2303 case BT_GRAPH_STATUS_CANCELED
:
2304 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
2306 case BT_GRAPH_STATUS_AGAIN
:
2307 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
2309 case BT_GRAPH_STATUS_END
:
2310 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
2312 case BT_GRAPH_STATUS_NOMEM
:
2313 status
= BT_NOTIFICATION_ITERATOR_STATUS_NOMEM
;
2315 case BT_GRAPH_STATUS_OK
:
2316 status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
;
2317 assert(bt_notification_iterator_borrow_current_notification(iterator
));
2321 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
2324 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
2325 /* Error/exception: restore old notification */
2326 bt_notification_iterator_replace_current_notification(
2327 iterator
, old_notif
);
2334 BT_LOGF("Unknown notification iterator type: addr=%p, type=%d",
2335 iterator
, iterator
->type
);
2343 struct bt_component
*bt_private_connection_notification_iterator_get_component(
2344 struct bt_notification_iterator
*iterator
)
2346 struct bt_component
*comp
= NULL
;
2347 struct bt_notification_iterator_private_connection
*iter_priv_conn
;
2350 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
2354 if (iterator
->type
!= BT_NOTIFICATION_ITERATOR_TYPE_PRIVATE_CONNECTION
) {
2355 BT_LOGW_STR("Invalid parameter: notification iterator was not created from a private connection.");
2359 iter_priv_conn
= (void *) iterator
;
2360 comp
= bt_get(iter_priv_conn
->upstream_component
);
2366 struct bt_private_component
*
2367 bt_private_connection_private_notification_iterator_get_private_component(
2368 struct bt_private_connection_private_notification_iterator
*private_iterator
)
2370 return bt_private_component_from_component(
2371 bt_private_connection_notification_iterator_get_component(
2372 (void *) bt_private_connection_notification_iterator_borrow_from_private(private_iterator
)));
2376 void bt_output_port_notification_iterator_destroy(struct bt_object
*obj
)
2378 struct bt_notification_iterator_output_port
*iterator
=
2379 (void *) container_of(obj
, struct bt_notification_iterator
, base
);
2381 BT_LOGD("Destroying output port notification iterator object: addr=%p",
2383 BT_LOGD_STR("Putting graph.");
2384 bt_put(iterator
->graph
);
2385 BT_LOGD_STR("Putting output port.");
2386 bt_put(iterator
->output_port
);
2387 BT_LOGD_STR("Putting colander sink component.");
2388 bt_put(iterator
->colander
);
2389 destroy_base_notification_iterator(obj
);
2392 struct bt_notification_iterator
*bt_output_port_notification_iterator_create(
2393 struct bt_port
*output_port
,
2394 const char *colander_component_name
,
2395 const enum bt_notification_type
*notification_types
)
2397 struct bt_notification_iterator
*iterator_base
= NULL
;
2398 struct bt_notification_iterator_output_port
*iterator
= NULL
;
2399 struct bt_component_class
*colander_comp_cls
= NULL
;
2400 struct bt_component
*output_port_comp
= NULL
;
2401 struct bt_component
*colander_comp
;
2402 struct bt_graph
*graph
= NULL
;
2403 enum bt_graph_status graph_status
;
2404 const char *colander_comp_name
;
2405 struct bt_port
*colander_in_port
= NULL
;
2406 struct bt_component_class_sink_colander_data colander_data
;
2409 BT_LOGW_STR("Invalid parameter: port is NULL.");
2413 if (bt_port_get_type(output_port
) != BT_PORT_TYPE_OUTPUT
) {
2414 BT_LOGW_STR("Invalid parameter: port is not an output port.");
2418 output_port_comp
= bt_port_get_component(output_port
);
2419 if (!output_port_comp
) {
2420 BT_LOGW("Cannot get output port's component: "
2421 "port-addr=%p, port-name=\"%s\"",
2422 output_port
, bt_port_get_name(output_port
));
2426 graph
= bt_component_get_graph(output_port_comp
);
2429 /* Create notification iterator */
2430 BT_LOGD("Creating notification iterator on output port: "
2431 "comp-addr=%p, comp-name\"%s\", port-addr=%p, port-name=\"%s\"",
2432 output_port_comp
, bt_component_get_name(output_port_comp
),
2433 output_port
, bt_port_get_name(output_port
));
2434 iterator
= g_new0(struct bt_notification_iterator_output_port
, 1);
2436 BT_LOGE_STR("Failed to allocate one output port notification iterator.");
2440 init_notification_iterator((void *) iterator
,
2441 BT_NOTIFICATION_ITERATOR_TYPE_OUTPUT_PORT
,
2442 bt_output_port_notification_iterator_destroy
);
2444 /* Create colander component */
2445 colander_comp_cls
= bt_component_class_sink_colander_get();
2446 if (!colander_comp_cls
) {
2447 BT_LOGW("Cannot get colander sink component class.");
2451 BT_MOVE(iterator
->graph
, graph
);
2452 iterator_base
= (void *) iterator
;
2453 colander_comp_name
=
2454 colander_component_name
? colander_component_name
: "colander";
2455 colander_data
.notification
= &iterator_base
->current_notification
;
2456 colander_data
.notification_types
= notification_types
;
2457 graph_status
= bt_graph_add_component_with_init_method_data(
2458 iterator
->graph
, colander_comp_cls
, colander_comp_name
,
2459 NULL
, &colander_data
, &iterator
->colander
);
2460 if (graph_status
!= BT_GRAPH_STATUS_OK
) {
2461 BT_LOGW("Cannot add colander sink component to graph: "
2462 "graph-addr=%p, name=\"%s\", graph-status=%s",
2463 iterator
->graph
, colander_comp_name
,
2464 bt_graph_status_string(graph_status
));
2469 * Connect provided output port to the colander component's
2472 colander_in_port
= bt_component_sink_get_input_port_by_index(
2473 iterator
->colander
, 0);
2474 assert(colander_in_port
);
2475 graph_status
= bt_graph_connect_ports(iterator
->graph
,
2476 output_port
, colander_in_port
, NULL
);
2477 if (graph_status
!= BT_GRAPH_STATUS_OK
) {
2478 BT_LOGW("Cannot add colander sink component to graph: "
2479 "graph-addr=%p, name=\"%s\", graph-status=%s",
2480 iterator
->graph
, colander_comp_name
,
2481 bt_graph_status_string(graph_status
));
2486 * At this point everything went fine. Make the graph
2487 * nonconsumable forever so that only this notification iterator
2488 * can consume (thanks to bt_graph_consume_sink_no_check()).
2489 * This avoids leaking the notification created by the colander
2490 * sink and moved to the base notification iterator's current
2491 * notification member.
2493 bt_graph_set_can_consume(iterator
->graph
, BT_FALSE
);
2497 if (iterator
&& iterator
->graph
&& iterator
->colander
) {
2500 /* Remove created colander component from graph if any */
2501 colander_comp
= iterator
->colander
;
2502 BT_PUT(iterator
->colander
);
2505 * At this point the colander component's reference
2506 * count is 0 because iterator->colander was the only
2507 * owner. We also know that it is not connected because
2508 * this is the last operation before this function
2511 * Since we honor the preconditions here,
2512 * bt_graph_remove_unconnected_component() always
2515 ret
= bt_graph_remove_unconnected_component(iterator
->graph
,
2523 bt_put(colander_in_port
);
2524 bt_put(colander_comp_cls
);
2525 bt_put(output_port_comp
);
2527 return (void *) iterator
;
2530 struct bt_notification_iterator
*
2531 bt_private_connection_notification_iterator_from_private(
2532 struct bt_private_connection_private_notification_iterator
*private_notification_iterator
)
2535 bt_private_connection_notification_iterator_borrow_from_private(
2536 private_notification_iterator
));