diff options
author | Xavi Garcia Mena <xavi.garcia.mena@canonical.com> | 2016-03-07 10:13:52 +0000 |
---|---|---|
committer | CI Train Bot <ci-train-bot@canonical.com> | 2016-03-07 10:13:52 +0000 |
commit | a03ba9b8fe38bad63a5b14096dfadc7341e1eac6 (patch) | |
tree | 4f9756dc0694d4fd2fe25087317a80a9f468205d | |
parent | 5e59aeb7d963648d0975799ad69da865dc552bf7 (diff) | |
parent | 1cc5e45c976b428730e928fa10c57288129ba0e1 (diff) | |
download | ayatana-indicator-sound-a03ba9b8fe38bad63a5b14096dfadc7341e1eac6.tar.gz ayatana-indicator-sound-a03ba9b8fe38bad63a5b14096dfadc7341e1eac6.tar.bz2 ayatana-indicator-sound-a03ba9b8fe38bad63a5b14096dfadc7341e1eac6.zip |
Add changes to show up the microphone controls when an external microphone is detected.
Approved by: PS Jenkins bot, Charles Kerr
-rw-r--r-- | src/volume-control-pulse.vala | 33 | ||||
-rw-r--r-- | tests/integration/indicator-sound-test-base.cpp | 102 | ||||
-rw-r--r-- | tests/integration/indicator-sound-test-base.h | 6 | ||||
-rw-r--r-- | tests/integration/test-indicator.cpp | 162 |
4 files changed, 281 insertions, 22 deletions
diff --git a/src/volume-control-pulse.vala b/src/volume-control-pulse.vala index c8a6071..653a1bd 100644 --- a/src/volume-control-pulse.vala +++ b/src/volume-control-pulse.vala @@ -54,6 +54,8 @@ public class VolumeControlPulse : VolumeControl private double _account_service_volume = 0.0; private VolumeControl.ActiveOutput _active_output = VolumeControl.ActiveOutput.SPEAKERS; private AccountsServiceAccess _accounts_service_access; + private bool _external_mic_detected = false; + private bool _source_sink_mic_activated = false; /** true when a microphone is active **/ public override bool active_mic { get; private set; default = false; } @@ -139,6 +141,22 @@ public class VolumeControlPulse : VolumeControl return ret_output; } + private bool is_external_mic (SourceInfo? sink) { + if (sink.name.contains ("indicator_sound_test_mic")) { + return true; + } + if (sink.active_port != null && + ( (sink.active_port.name.contains ("headphone") || + sink.active_port.name.contains ("headset") || + sink.active_port.name.contains ("mic") ) && + (!sink.active_port.name.contains ("internal") && + !sink.active_port.name.contains ("builtin")) )) { + return true; + } + return false; + } + + /* PulseAudio logic*/ private void context_events_cb (Context c, Context.SubscriptionEventType t, uint32 index) { @@ -180,7 +198,8 @@ public class VolumeControlPulse : VolumeControl break; case Context.SubscriptionEventType.REMOVE: - this.active_mic = false; + this._source_sink_mic_activated = false; + this.active_mic = _external_mic_detected; break; } break; @@ -229,6 +248,14 @@ public class VolumeControlPulse : VolumeControl if (i == null) return; + if (is_external_mic (i)) { + this.active_mic = true; + _external_mic_detected = true; + } else { + this.active_mic = _source_sink_mic_activated; + _external_mic_detected = false; + } + if (_mic_volume != volume_to_double (i.volume.values[0])) { _mic_volume = volume_to_double (i.volume.values[0]); @@ -434,8 +461,10 @@ public class VolumeControlPulse : VolumeControl return; unowned string role = i.proplist.gets (PulseAudio.Proplist.PROP_MEDIA_ROLE); - if (role == "phone" || role == "production") + if (role == "phone" || role == "production") { this.active_mic = true; + this._source_sink_mic_activated = true; + } } private void context_state_callback (Context c) diff --git a/tests/integration/indicator-sound-test-base.cpp b/tests/integration/indicator-sound-test-base.cpp index cf60868..9225c1d 100644 --- a/tests/integration/indicator-sound-test-base.cpp +++ b/tests/integration/indicator-sound-test-base.cpp @@ -296,6 +296,7 @@ void IndicatorSoundTestBase::startPulseDesktop(DevicePortType speakerPort, Devic << "-n" << QString("--load=module-null-sink sink_name=indicator_sound_test_speaker sink_properties=device.bus=%1").arg(getDevicePortString(speakerPort)) << QString("--load=module-null-sink sink_name=indicator_sound_test_headphones sink_properties=device.bus=%1").arg(getDevicePortString(headphonesPort)) + << QString("--load=module-null-sink sink_name=indicator_sound_test_mic") << "--log-target=file:/tmp/pulse-daemon.log" << "--load=module-dbus-protocol" << "--load=module-native-protocol-tcp auth-ip-acl=127.0.0.1" @@ -327,6 +328,7 @@ void IndicatorSoundTestBase::startPulsePhone(DevicePortType speakerPort, DeviceP << "-n" << QString("--load=module-null-sink sink_name=indicator_sound_test_speaker sink_properties=device.bus=%1").arg(getDevicePortString(speakerPort)) << QString("--load=module-null-sink sink_name=indicator_sound_test_headphones sink_properties=device.bus=%1").arg(getDevicePortString(headphonesPort)) + << QString("--load=module-null-sink sink_name=indicator_sound_test_mic") << "--log-target=file:/tmp/pulse-daemon.log" << QString("--load=module-stream-restore restore_device=false restore_muted=false fallback_table=%1").arg(STREAM_RESTORE_TABLE) << "--load=module-dbus-protocol" @@ -411,6 +413,20 @@ unity::gmenuharness::MenuItemMatcher IndicatorSoundTestBase::volumeSlider(double .pass_through_double_attribute("action", volume); } +unity::gmenuharness::MenuItemMatcher IndicatorSoundTestBase::micSlider(double volume, QString const &label) +{ + return mh::MenuItemMatcher() + .label(label.toStdString()) + .round_doubles(0.1) + .double_attribute("min-value", 0.0) + .double_attribute("max-value", 1.0) + .double_attribute("step", 0.01) + .string_attribute("x-canonical-type", "com.canonical.unity.slider") + .themed_icon("max-icon", {"audio-input-microphone-high-panel", "audio-input-microphone-high", "audio-input-microphone", "audio-input", "audio"}) + .themed_icon("min-icon", {"audio-input-microphone-low-zero-panel", "audio-input-microphone-low-zero", "audio-input-microphone-low", "audio-input-microphone", "audio-input", "audio"}) + .pass_through_double_attribute("action", volume); +} + unity::gmenuharness::MenuItemMatcher IndicatorSoundTestBase::silentModeSwitch(bool toggled) { return mh::MenuItemMatcher::checkbox() @@ -673,53 +689,99 @@ int IndicatorSoundTestBase::getNotificationID(QVariantList call) return id; } -bool IndicatorSoundTestBase::activateHeadphones(bool headphonesActive) +bool IndicatorSoundTestBase::setDefaultSinkOrSource(bool runForSinks, const QString & active, const QStringList & inactive) { + QString setDefaultCommand = runForSinks ? "set-default-sink" : "set-default-source"; + QString suspendCommand = "suspend-sink"; + QProcess pacltProcess; - QString defaultSinkName = "indicator_sound_test_speaker"; - QString suspendedSinkName = "indicator_sound_test_headphones"; - if (headphonesActive) - { - defaultSinkName = "indicator_sound_test_headphones"; - suspendedSinkName = "indicator_sound_test_speaker"; - } + QString activeSinkOrSource = runForSinks ? active : active + ".monitor"; pacltProcess.start("pactl", QStringList() << "-s" << "127.0.0.1" - << "set-default-sink" - << defaultSinkName); + << setDefaultCommand + << activeSinkOrSource); if (!pacltProcess.waitForStarted()) + { return false; + } if (!pacltProcess.waitForFinished()) + { return false; + } pacltProcess.start("pactl", QStringList() << "-s" << "127.0.0.1" - << "suspend-sink" - << defaultSinkName + << suspendCommand + << active << "0"); if (!pacltProcess.waitForStarted()) + { return false; + } if (!pacltProcess.waitForFinished()) + { return false; + } - pacltProcess.start("pactl", QStringList() << "-s" - << "127.0.0.1" - << "suspend-sink" - << suspendedSinkName - << "1"); - if (!pacltProcess.waitForStarted()) + if (pacltProcess.exitCode() != 0) + { return false; + } + for (int i = 0; i < inactive.size(); ++i) + { + pacltProcess.start("pactl", QStringList() << "-s" + << "127.0.0.1" + << suspendCommand + << inactive.at(i) + << "1"); + if (!pacltProcess.waitForStarted()) + { + return false; + } - if (!pacltProcess.waitForFinished()) - return false; + if (!pacltProcess.waitForFinished()) + { + return false; + } + if (pacltProcess.exitCode() != 0) + { + return false; + } + } return pacltProcess.exitCode() == 0; } +bool IndicatorSoundTestBase::activateHeadphones(bool headphonesActive) +{ + QString defaultSinkName = "indicator_sound_test_speaker"; + QStringList suspendedSinks = { "indicator_sound_test_mic", "indicator_sound_test_headphones" }; + if (headphonesActive) + { + defaultSinkName = "indicator_sound_test_headphones"; + suspendedSinks = QStringList{ "indicator_sound_test_speaker", "indicator_sound_test_mic" }; + } + return setDefaultSinkOrSource(true, defaultSinkName, suspendedSinks); +} + +bool IndicatorSoundTestBase::plugExternalMic(bool activate) +{ + QString defaultSinkName = "indicator_sound_test_mic"; + QStringList suspendedSinks = { "indicator_sound_test_speaker", "indicator_sound_test_headphones" }; + + if (!activate) + { + defaultSinkName = "indicator_sound_test_speaker"; + suspendedSinks = QStringList{ "indicator_sound_test_mic", "indicator_sound_test_headphones" }; + } + + return setDefaultSinkOrSource(false, defaultSinkName, suspendedSinks); +} + QString IndicatorSoundTestBase::getDevicePortString(DevicePortType port) { QString portString; diff --git a/tests/integration/indicator-sound-test-base.h b/tests/integration/indicator-sound-test-base.h index 5c36031..5b3545a 100644 --- a/tests/integration/indicator-sound-test-base.h +++ b/tests/integration/indicator-sound-test-base.h @@ -102,6 +102,8 @@ protected: static unity::gmenuharness::MenuItemMatcher volumeSlider(double volume, QString const &label); + static unity::gmenuharness::MenuItemMatcher micSlider(double volume, QString const &label); + static unity::gmenuharness::MenuItemMatcher silentModeSwitch(bool toggled); bool waitMenuChange(); @@ -132,6 +134,10 @@ protected: bool activateHeadphones(bool headphonesActive); + bool plugExternalMic(bool activate); + + bool setDefaultSinkOrSource(bool runForSinks, const QString & active, const QStringList & inactive); + QString getDevicePortString(DevicePortType port); void checkPortDevicesLabels(DevicePortType speakerPort, DevicePortType headphonesPort); diff --git a/tests/integration/test-indicator.cpp b/tests/integration/test-indicator.cpp index bc426aa..eff1516 100644 --- a/tests/integration/test-indicator.cpp +++ b/tests/integration/test-indicator.cpp @@ -32,6 +32,168 @@ class TestIndicator: public IndicatorSoundTestBase { }; +TEST_F(TestIndicator, PhoneTestExternalMicInOut) +{ + double INITIAL_VOLUME = 0.0; + + ASSERT_NO_THROW(startAccountsService()); + EXPECT_TRUE(clearGSettingsPlayers()); + ASSERT_NO_THROW(startPulsePhone()); + + // initialize volumes in pulseaudio + EXPECT_TRUE(setStreamRestoreVolume("alert", INITIAL_VOLUME)); + + // start now the indicator, so it picks the new volumes + ASSERT_NO_THROW(startIndicator()); + + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-scroll-action", "indicator.scroll") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .string_attribute("submenu-action", "indicator.indicator-shown") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(silentModeSwitch(false)) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + .action("indicator.phone-settings") + ) + ).match()); + + EXPECT_TRUE(plugExternalMic(true)); + + // check that we have the mic slider now. + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-scroll-action", "indicator.scroll") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .string_attribute("submenu-action", "indicator.indicator-shown") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(silentModeSwitch(false)) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + .item(micSlider(1.0, "Microphone Volume")) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + .action("indicator.phone-settings") + ) + ).match()); + + + // unplug the external mic + EXPECT_TRUE(plugExternalMic(false)); + + // and check that there's no mic slider + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-scroll-action", "indicator.scroll") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .string_attribute("submenu-action", "indicator.indicator-shown") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(silentModeSwitch(false)) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + .action("indicator.phone-settings") + ) + ).match()); +} + +TEST_F(TestIndicator, DesktopTestExternalMicInOut) +{ + double INITIAL_VOLUME = 0.0; + + ASSERT_NO_THROW(startAccountsService()); + EXPECT_TRUE(clearGSettingsPlayers()); + ASSERT_NO_THROW(startPulseDesktop()); + + // initialize volumes in pulseaudio + EXPECT_FALSE(setStreamRestoreVolume("alert", INITIAL_VOLUME)); + EXPECT_TRUE(setSinkVolume(INITIAL_VOLUME)); + + // start now the indicator, so it picks the new volumes + ASSERT_NO_THROW(startIndicator()); + + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); + + EXPECT_TRUE(plugExternalMic(true)); + + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + .item(micSlider(1.0, "Microphone Volume")) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); + + EXPECT_TRUE(plugExternalMic(false)); + + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); +} + TEST_F(TestIndicator, DISABLED_PhoneChangeRoleVolume) { double INITIAL_VOLUME = 0.0; |