// Copyright 2016 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <gtest/gtest.h> #include <stdio.h> #include <syslog.h> #include <vector> #include <map> extern "C" { #include "cras_observer.c" } namespace { static size_t cras_alert_destroy_called; static size_t cras_alert_create_called; static std::vector<struct cras_alert *> cras_alert_create_return_values; typedef std::map<struct cras_alert *, void *> alert_callback_map; static alert_callback_map cras_alert_create_prepare_map; static alert_callback_map cras_alert_add_callback_map; typedef std::map<struct cras_alert *, unsigned int> alert_flags_map; static alert_flags_map cras_alert_create_flags_map; static struct cras_alert *cras_alert_pending_alert_value; static void *cras_alert_pending_data_value = NULL; static size_t cras_alert_pending_data_size_value; static size_t cras_iodev_list_update_device_list_called; static std::vector<void *> cb_context; static size_t cb_output_volume_changed_called; static std::vector<int32_t> cb_output_volume_changed_volume; static size_t cb_output_mute_changed_called; static std::vector<int> cb_output_mute_changed_muted; static std::vector<int> cb_output_mute_changed_user_muted; static std::vector<int> cb_output_mute_changed_mute_locked; static size_t cb_capture_gain_changed_called; static std::vector<int32_t> cb_capture_gain_changed_gain; static size_t cb_capture_mute_changed_called; static std::vector<int> cb_capture_mute_changed_muted; static std::vector<int> cb_capture_mute_changed_mute_locked; static size_t cb_nodes_changed_called; static size_t cb_active_node_changed_called; static std::vector<enum CRAS_STREAM_DIRECTION> cb_active_node_changed_dir; static std::vector<cras_node_id_t> cb_active_node_changed_node_id; static size_t cb_output_node_volume_changed_called; static std::vector<cras_node_id_t> cb_output_node_volume_changed_node_id; static std::vector<int32_t> cb_output_node_volume_changed_volume; static size_t cb_node_left_right_swapped_changed_called; static std::vector<cras_node_id_t> cb_node_left_right_swapped_changed_node_id; static std::vector<int> cb_node_left_right_swapped_changed_swapped; static size_t cb_input_node_gain_changed_called; static std::vector<cras_node_id_t> cb_input_node_gain_changed_node_id; static std::vector<int32_t> cb_input_node_gain_changed_gain; static size_t cb_num_active_streams_changed_called; static std::vector<enum CRAS_STREAM_DIRECTION> cb_num_active_streams_changed_dir; static std::vector<uint32_t> cb_num_active_streams_changed_num; static void ResetStubData() { cras_alert_destroy_called = 0; cras_alert_create_called = 0; cras_alert_create_return_values.clear(); cras_alert_create_prepare_map.clear(); cras_alert_create_flags_map.clear(); cras_alert_add_callback_map.clear(); cras_alert_pending_alert_value = NULL; cras_alert_pending_data_size_value = 0; if (cras_alert_pending_data_value) { free(cras_alert_pending_data_value); cras_alert_pending_data_value = NULL; } cras_iodev_list_update_device_list_called = 0; cb_context.clear(); cb_output_volume_changed_called = 0; cb_output_volume_changed_volume.clear(); cb_output_mute_changed_called = 0; cb_output_mute_changed_muted.clear(); cb_output_mute_changed_user_muted.clear(); cb_output_mute_changed_mute_locked.clear(); cb_capture_gain_changed_called = 0; cb_capture_gain_changed_gain.clear(); cb_capture_mute_changed_called = 0; cb_capture_mute_changed_muted.clear(); cb_capture_mute_changed_mute_locked.clear(); cb_nodes_changed_called = 0; cb_active_node_changed_called = 0; cb_active_node_changed_dir.clear(); cb_active_node_changed_node_id.clear(); cb_output_node_volume_changed_called = 0; cb_output_node_volume_changed_node_id.clear(); cb_output_node_volume_changed_volume.clear(); cb_node_left_right_swapped_changed_called = 0; cb_node_left_right_swapped_changed_node_id.clear(); cb_node_left_right_swapped_changed_swapped.clear(); cb_input_node_gain_changed_called = 0; cb_input_node_gain_changed_node_id.clear(); cb_input_node_gain_changed_gain.clear(); cb_num_active_streams_changed_called = 0; cb_num_active_streams_changed_dir.clear(); cb_num_active_streams_changed_num.clear(); } /* System output volume changed. */ void cb_output_volume_changed(void *context, int32_t volume) { cb_output_volume_changed_called++; cb_context.push_back(context); cb_output_volume_changed_volume.push_back(volume); } /* System output mute changed. */ void cb_output_mute_changed(void *context, int muted, int user_muted, int mute_locked) { cb_output_mute_changed_called++; cb_context.push_back(context); cb_output_mute_changed_muted.push_back(muted); cb_output_mute_changed_user_muted.push_back(user_muted); cb_output_mute_changed_mute_locked.push_back(mute_locked); } /* System input/capture gain changed. */ void cb_capture_gain_changed(void *context, int32_t gain) { cb_capture_gain_changed_called++; cb_context.push_back(context); cb_capture_gain_changed_gain.push_back(gain); } /* System input/capture mute changed. */ void cb_capture_mute_changed(void *context, int muted, int mute_locked) { cb_capture_mute_changed_called++; cb_context.push_back(context); cb_capture_mute_changed_muted.push_back(muted); cb_capture_mute_changed_mute_locked.push_back(mute_locked); } /* Device or node topology changed. */ void cb_nodes_changed(void *context) { cb_nodes_changed_called++; cb_context.push_back(context); } /* Active node changed. A notification is sent for every change. * When there is no active node, node_id is 0. */ void cb_active_node_changed(void *context, enum CRAS_STREAM_DIRECTION dir, cras_node_id_t node_id) { cb_active_node_changed_called++; cb_context.push_back(context); cb_active_node_changed_dir.push_back(dir); cb_active_node_changed_node_id.push_back(node_id); } /* Output node volume changed. */ void cb_output_node_volume_changed(void *context, cras_node_id_t node_id, int32_t volume) { cb_output_node_volume_changed_called++; cb_context.push_back(context); cb_output_node_volume_changed_node_id.push_back(node_id); cb_output_node_volume_changed_volume.push_back(volume); } /* Node left/right swapped state change. */ void cb_node_left_right_swapped_changed(void *context, cras_node_id_t node_id, int swapped) { cb_node_left_right_swapped_changed_called++; cb_context.push_back(context); cb_node_left_right_swapped_changed_node_id.push_back(node_id); cb_node_left_right_swapped_changed_swapped.push_back(swapped); } /* Input gain changed. */ void cb_input_node_gain_changed(void *context, cras_node_id_t node_id, int32_t gain) { cb_input_node_gain_changed_called++; cb_context.push_back(context); cb_input_node_gain_changed_node_id.push_back(node_id); cb_input_node_gain_changed_gain.push_back(gain); } /* Number of active streams changed. */ void cb_num_active_streams_changed(void *context, enum CRAS_STREAM_DIRECTION dir, uint32_t num_active_streams) { cb_num_active_streams_changed_called++; cb_context.push_back(context); cb_num_active_streams_changed_dir.push_back(dir); cb_num_active_streams_changed_num.push_back(num_active_streams); } class ObserverTest : public testing::Test { protected: virtual void SetUp() { int rc; ResetStubData(); rc = cras_observer_server_init(); ASSERT_EQ(0, rc); EXPECT_EQ(15, cras_alert_create_called); EXPECT_EQ(reinterpret_cast<void *>(output_volume_alert), cras_alert_add_callback_map[g_observer->alerts.output_volume]); EXPECT_EQ(reinterpret_cast<void *>(output_mute_alert), cras_alert_add_callback_map[g_observer->alerts.output_mute]); EXPECT_EQ(reinterpret_cast<void *>(capture_gain_alert), cras_alert_add_callback_map[g_observer->alerts.capture_gain]); EXPECT_EQ(reinterpret_cast<void *>(capture_mute_alert), cras_alert_add_callback_map[g_observer->alerts.capture_mute]); EXPECT_EQ(reinterpret_cast<void *>(nodes_alert), cras_alert_add_callback_map[g_observer->alerts.nodes]); EXPECT_EQ(reinterpret_cast<void *>(nodes_prepare), cras_alert_create_prepare_map[g_observer->alerts.nodes]); EXPECT_EQ(reinterpret_cast<void *>(active_node_alert), cras_alert_add_callback_map[g_observer->alerts.active_node]); EXPECT_EQ(CRAS_ALERT_FLAG_KEEP_ALL_DATA, cras_alert_create_flags_map[g_observer->alerts.active_node]); EXPECT_EQ(reinterpret_cast<void *>(output_node_volume_alert), cras_alert_add_callback_map[g_observer->alerts.output_node_volume]); EXPECT_EQ(reinterpret_cast<void *>(node_left_right_swapped_alert), cras_alert_add_callback_map[g_observer->alerts.node_left_right_swapped]); EXPECT_EQ(reinterpret_cast<void *>(input_node_gain_alert), cras_alert_add_callback_map[g_observer->alerts.input_node_gain]); EXPECT_EQ(reinterpret_cast<void *>(num_active_streams_alert), cras_alert_add_callback_map[g_observer->alerts.num_active_streams[ CRAS_STREAM_OUTPUT]]); EXPECT_EQ(reinterpret_cast<void *>(num_active_streams_alert), cras_alert_add_callback_map[g_observer->alerts.num_active_streams[ CRAS_STREAM_INPUT]]); EXPECT_EQ(reinterpret_cast<void *>(num_active_streams_alert), cras_alert_add_callback_map[g_observer->alerts.num_active_streams[ CRAS_STREAM_POST_MIX_PRE_DSP]]); EXPECT_EQ(reinterpret_cast<void *>(suspend_changed_alert), cras_alert_add_callback_map[g_observer->alerts.suspend_changed]); EXPECT_EQ(reinterpret_cast<void *>(hotword_triggered_alert), cras_alert_add_callback_map[g_observer->alerts.hotword_triggered]); EXPECT_EQ(reinterpret_cast<void *>(non_empty_audio_state_changed_alert), cras_alert_add_callback_map[ g_observer->alerts.non_empty_audio_state_changed]); cras_observer_get_ops(NULL, &ops1_); EXPECT_NE(0, cras_observer_ops_are_empty(&ops1_)); cras_observer_get_ops(NULL, &ops2_); EXPECT_NE(0, cras_observer_ops_are_empty(&ops2_)); context1_ = reinterpret_cast<void *>(1); context2_ = reinterpret_cast<void *>(2); } virtual void TearDown() { cras_observer_server_free(); EXPECT_EQ(15, cras_alert_destroy_called); ResetStubData(); } void DoObserverAlert(cras_alert_cb alert, void *data) { client1_ = cras_observer_add(&ops1_, context1_); client2_ = cras_observer_add(&ops2_, context2_); ASSERT_NE(client1_, reinterpret_cast<struct cras_observer_client *>(NULL)); ASSERT_NE(client2_, reinterpret_cast<struct cras_observer_client *>(NULL)); ASSERT_NE(alert, reinterpret_cast<cras_alert_cb>(NULL)); alert(NULL, data); EXPECT_EQ(cb_context[0], context1_); EXPECT_EQ(cb_context[1], context2_); } void DoObserverRemoveClear(cras_alert_cb alert, void *data) { ASSERT_NE(alert, reinterpret_cast<cras_alert_cb>(NULL)); ASSERT_NE(client1_, reinterpret_cast<struct cras_observer_client *>(NULL)); ASSERT_NE(client2_, reinterpret_cast<struct cras_observer_client *>(NULL)); // Test observer removal. cras_observer_remove(client1_); cb_context.clear(); alert(NULL, data); EXPECT_EQ(cb_context[0], context2_); EXPECT_EQ(cb_context.size(), 1); // Clear out ops1_. cras_observer_get_ops(NULL, &ops1_); EXPECT_NE(0, cras_observer_ops_are_empty(&ops1_)); // Get the current value of ops2_ into ops1_. cras_observer_get_ops(client2_, &ops1_); EXPECT_EQ(0, memcmp((void *)&ops1_, (void *)&ops2_, sizeof(ops1_))); // Clear out opts for client2. cras_observer_get_ops(NULL, &ops2_); EXPECT_NE(0, cras_observer_ops_are_empty(&ops2_)); cras_observer_set_ops(client2_, &ops2_); cras_observer_remove(client2_); cb_context.clear(); alert(NULL, data); // No callbacks executed. EXPECT_EQ(cb_context.size(), 0); } struct cras_observer_client *client1_; struct cras_observer_client *client2_; struct cras_observer_ops ops1_; struct cras_observer_ops ops2_; void *context1_; void *context2_; }; TEST_F(ObserverTest, NotifyOutputVolume) { struct cras_observer_alert_data_volume *data; const int32_t volume = 100; cras_observer_notify_output_volume(volume); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.output_volume); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_volume *>( cras_alert_pending_data_value); EXPECT_EQ(data->volume, volume); ops1_.output_volume_changed = cb_output_volume_changed; ops2_.output_volume_changed = cb_output_volume_changed; DoObserverAlert(output_volume_alert, data); ASSERT_EQ(2, cb_output_volume_changed_called); EXPECT_EQ(cb_output_volume_changed_volume[0], volume); EXPECT_EQ(cb_output_volume_changed_volume[1], volume); DoObserverRemoveClear(output_volume_alert, data); }; TEST_F(ObserverTest, NotifyOutputMute) { struct cras_observer_alert_data_mute *data; const int muted = 1; const int user_muted = 0; const int mute_locked = 0; cras_observer_notify_output_mute(muted, user_muted, mute_locked); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.output_mute); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_mute *>( cras_alert_pending_data_value); EXPECT_EQ(data->muted, muted); EXPECT_EQ(data->user_muted, user_muted); EXPECT_EQ(data->mute_locked, mute_locked); ops1_.output_mute_changed = cb_output_mute_changed; ops2_.output_mute_changed = cb_output_mute_changed; DoObserverAlert(output_mute_alert, data); ASSERT_EQ(2, cb_output_mute_changed_called); EXPECT_EQ(cb_output_mute_changed_muted[0], muted); EXPECT_EQ(cb_output_mute_changed_muted[1], muted); EXPECT_EQ(cb_output_mute_changed_user_muted[0], user_muted); EXPECT_EQ(cb_output_mute_changed_user_muted[1], user_muted); EXPECT_EQ(cb_output_mute_changed_mute_locked[0], mute_locked); EXPECT_EQ(cb_output_mute_changed_mute_locked[1], mute_locked); DoObserverRemoveClear(output_mute_alert, data); }; TEST_F(ObserverTest, NotifyCaptureGain) { struct cras_observer_alert_data_volume *data; const int32_t gain = -20; cras_observer_notify_capture_gain(gain); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.capture_gain); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_volume *>( cras_alert_pending_data_value); EXPECT_EQ(data->volume, gain); ops1_.capture_gain_changed = cb_capture_gain_changed; ops2_.capture_gain_changed = cb_capture_gain_changed; DoObserverAlert(capture_gain_alert, data); ASSERT_EQ(2, cb_capture_gain_changed_called); EXPECT_EQ(cb_capture_gain_changed_gain[0], gain); EXPECT_EQ(cb_capture_gain_changed_gain[1], gain); DoObserverRemoveClear(capture_gain_alert, data); }; TEST_F(ObserverTest, NotifyCaptureMute) { struct cras_observer_alert_data_mute *data; const int muted = 1; const int mute_locked = 0; cras_observer_notify_capture_mute(muted, mute_locked); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.capture_mute); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_mute *>( cras_alert_pending_data_value); EXPECT_EQ(data->muted, muted); EXPECT_EQ(data->mute_locked, mute_locked); ops1_.capture_mute_changed = cb_capture_mute_changed; ops2_.capture_mute_changed = cb_capture_mute_changed; DoObserverAlert(capture_mute_alert, data); ASSERT_EQ(2, cb_capture_mute_changed_called); EXPECT_EQ(cb_capture_mute_changed_muted[0], muted); EXPECT_EQ(cb_capture_mute_changed_muted[1], muted); EXPECT_EQ(cb_capture_mute_changed_mute_locked[0], mute_locked); EXPECT_EQ(cb_capture_mute_changed_mute_locked[1], mute_locked); DoObserverRemoveClear(capture_mute_alert, data); }; TEST_F(ObserverTest, NotifyNodes) { cras_observer_notify_nodes(); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.nodes); ops1_.nodes_changed = cb_nodes_changed; ops2_.nodes_changed = cb_nodes_changed; DoObserverAlert(nodes_alert, NULL); ASSERT_EQ(2, cb_nodes_changed_called); DoObserverRemoveClear(nodes_alert, NULL); }; TEST_F(ObserverTest, NotifyActiveNode) { struct cras_observer_alert_data_active_node *data; const enum CRAS_STREAM_DIRECTION dir = CRAS_STREAM_INPUT; const cras_node_id_t node_id = 0x0001000100020002; cras_observer_notify_active_node(dir, node_id); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.active_node); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_active_node *>( cras_alert_pending_data_value); EXPECT_EQ(data->node_id, node_id); EXPECT_EQ(data->direction, dir); ops1_.active_node_changed = cb_active_node_changed; ops2_.active_node_changed = cb_active_node_changed; DoObserverAlert(active_node_alert, data); ASSERT_EQ(2, cb_active_node_changed_called); EXPECT_EQ(cb_active_node_changed_dir[0], dir); EXPECT_EQ(cb_active_node_changed_dir[1], dir); EXPECT_EQ(cb_active_node_changed_node_id[0], node_id); EXPECT_EQ(cb_active_node_changed_node_id[1], node_id); DoObserverRemoveClear(active_node_alert, data); }; TEST_F(ObserverTest, NotifyOutputNodeVolume) { struct cras_observer_alert_data_node_volume *data; const cras_node_id_t node_id = 0x0001000100020002; const int32_t volume = 100; cras_observer_notify_output_node_volume(node_id, volume); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.output_node_volume); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_node_volume *>( cras_alert_pending_data_value); EXPECT_EQ(data->node_id, node_id); EXPECT_EQ(data->volume, volume); ops1_.output_node_volume_changed = cb_output_node_volume_changed; ops2_.output_node_volume_changed = cb_output_node_volume_changed; DoObserverAlert(output_node_volume_alert, data); ASSERT_EQ(2, cb_output_node_volume_changed_called); EXPECT_EQ(cb_output_node_volume_changed_volume[0], volume); EXPECT_EQ(cb_output_node_volume_changed_volume[1], volume); EXPECT_EQ(cb_output_node_volume_changed_node_id[0], node_id); EXPECT_EQ(cb_output_node_volume_changed_node_id[1], node_id); DoObserverRemoveClear(output_node_volume_alert, data); }; TEST_F(ObserverTest, NotifyNodeLeftRightSwapped) { struct cras_observer_alert_data_node_lr_swapped *data; const cras_node_id_t node_id = 0x0001000100020002; const int swapped = 1; cras_observer_notify_node_left_right_swapped(node_id, swapped); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.node_left_right_swapped); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_node_lr_swapped *>( cras_alert_pending_data_value); EXPECT_EQ(data->node_id, node_id); EXPECT_EQ(data->swapped, swapped); ops1_.node_left_right_swapped_changed = cb_node_left_right_swapped_changed; ops2_.node_left_right_swapped_changed = cb_node_left_right_swapped_changed; DoObserverAlert(node_left_right_swapped_alert, data); ASSERT_EQ(2, cb_node_left_right_swapped_changed_called); EXPECT_EQ(cb_node_left_right_swapped_changed_swapped[0], swapped); EXPECT_EQ(cb_node_left_right_swapped_changed_swapped[1], swapped); EXPECT_EQ(cb_node_left_right_swapped_changed_node_id[0], node_id); EXPECT_EQ(cb_node_left_right_swapped_changed_node_id[1], node_id); DoObserverRemoveClear(node_left_right_swapped_alert, data); }; TEST_F(ObserverTest, NotifyInputNodeGain) { struct cras_observer_alert_data_node_volume *data; const cras_node_id_t node_id = 0x0001000100020002; const int32_t gain = -20; cras_observer_notify_input_node_gain(node_id, gain); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.input_node_gain); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_node_volume *>( cras_alert_pending_data_value); EXPECT_EQ(data->node_id, node_id); EXPECT_EQ(data->volume, gain); ops1_.input_node_gain_changed = cb_input_node_gain_changed; ops2_.input_node_gain_changed = cb_input_node_gain_changed; DoObserverAlert(input_node_gain_alert, data); ASSERT_EQ(2, cb_input_node_gain_changed_called); EXPECT_EQ(cb_input_node_gain_changed_gain[0], gain); EXPECT_EQ(cb_input_node_gain_changed_gain[1], gain); EXPECT_EQ(cb_input_node_gain_changed_node_id[0], node_id); EXPECT_EQ(cb_input_node_gain_changed_node_id[1], node_id); DoObserverRemoveClear(input_node_gain_alert, data); }; TEST_F(ObserverTest, NotifySuspendChanged) { struct cras_observer_alert_data_suspend *data; cras_observer_notify_suspend_changed(1); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.suspend_changed); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_suspend *>( cras_alert_pending_data_value); EXPECT_EQ(data->suspended, 1); cras_observer_notify_suspend_changed(0); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.suspend_changed); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_suspend *>( cras_alert_pending_data_value); EXPECT_EQ(data->suspended, 0); } TEST_F(ObserverTest, NotifyNumActiveStreams) { struct cras_observer_alert_data_streams *data; const enum CRAS_STREAM_DIRECTION dir = CRAS_STREAM_INPUT; const uint32_t active_streams = 10; cras_observer_notify_num_active_streams(dir, active_streams); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.num_active_streams[CRAS_STREAM_INPUT]); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_streams *>( cras_alert_pending_data_value); EXPECT_EQ(data->num_active_streams, active_streams); EXPECT_EQ(data->direction, dir); ops1_.num_active_streams_changed = cb_num_active_streams_changed; ops2_.num_active_streams_changed = cb_num_active_streams_changed; DoObserverAlert(num_active_streams_alert, data); ASSERT_EQ(2, cb_num_active_streams_changed_called); EXPECT_EQ(cb_num_active_streams_changed_dir[0], dir); EXPECT_EQ(cb_num_active_streams_changed_dir[1], dir); EXPECT_EQ(cb_num_active_streams_changed_num[0], active_streams); EXPECT_EQ(cb_num_active_streams_changed_num[1], active_streams); DoObserverRemoveClear(num_active_streams_alert, data); }; TEST_F(ObserverTest, NotifyHotwordTriggered) { struct cras_observer_alert_data_hotword_triggered *data; cras_observer_notify_hotword_triggered(100, 200); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.hotword_triggered); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_alert_data_hotword_triggered *>( cras_alert_pending_data_value); EXPECT_EQ(data->tv_sec, 100); EXPECT_EQ(data->tv_nsec, 200); } TEST_F(ObserverTest, NonEmpyAudioStateChanged) { struct cras_observer_non_empty_audio_state *data; cras_observer_notify_non_empty_audio_state_changed(1); EXPECT_EQ(cras_alert_pending_alert_value, g_observer->alerts.non_empty_audio_state_changed); ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data)); ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void *>(NULL)); data = reinterpret_cast<struct cras_observer_non_empty_audio_state *>( cras_alert_pending_data_value); EXPECT_EQ(data->non_empty, 1); } // Stubs extern "C" { void cras_alert_destroy(struct cras_alert *alert) { cras_alert_destroy_called++; } struct cras_alert *cras_alert_create(cras_alert_prepare prepare, unsigned int flags) { struct cras_alert *alert = NULL; cras_alert_create_called++; alert = reinterpret_cast<struct cras_alert*>(cras_alert_create_called); cras_alert_create_return_values.push_back(alert); cras_alert_create_flags_map[alert] = flags; cras_alert_create_prepare_map[alert] = reinterpret_cast<void *>(prepare); return alert; } int cras_alert_add_callback(struct cras_alert *alert, cras_alert_cb cb, void *arg) { cras_alert_add_callback_map[alert] = reinterpret_cast<void *>(cb); return 0; } void cras_alert_pending(struct cras_alert *alert) { cras_alert_pending_alert_value = alert; } void cras_alert_pending_data(struct cras_alert *alert, void *data, size_t data_size) { cras_alert_pending_alert_value = alert; cras_alert_pending_data_size_value = data_size; if (cras_alert_pending_data_value) free(cras_alert_pending_data_value); if (data) { cras_alert_pending_data_value = malloc(data_size); memcpy(cras_alert_pending_data_value, data, data_size); } else cras_alert_pending_data_value = NULL; } void cras_iodev_list_update_device_list() { cras_iodev_list_update_device_list_called++; } } // extern "C" } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); openlog(NULL, LOG_PERROR, LOG_USER); return RUN_ALL_TESTS(); }