aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavi Garcia Mena <xavi.garcia.mena@canonical.com>2016-03-07 10:13:52 +0000
committerCI Train Bot <ci-train-bot@canonical.com>2016-03-07 10:13:52 +0000
commita03ba9b8fe38bad63a5b14096dfadc7341e1eac6 (patch)
tree4f9756dc0694d4fd2fe25087317a80a9f468205d
parent5e59aeb7d963648d0975799ad69da865dc552bf7 (diff)
parent1cc5e45c976b428730e928fa10c57288129ba0e1 (diff)
downloadayatana-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.vala33
-rw-r--r--tests/integration/indicator-sound-test-base.cpp102
-rw-r--r--tests/integration/indicator-sound-test-base.h6
-rw-r--r--tests/integration/test-indicator.cpp162
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;