[Merge] lp:~rsalveti/telepathy-ofono/adding_support_for_hsp into lp:telepathy-ofono
Tiago Salem Herrmann
tiago.herrmann at canonical.com
Mon Aug 4 15:11:31 UTC 2014
Review: Needs Information
Diff comments:
> === modified file 'CMakeLists.txt'
> --- CMakeLists.txt 2014-06-27 13:35:18 +0000
> +++ CMakeLists.txt 2014-08-04 01:52:16 +0000
> @@ -33,12 +33,6 @@
> find_package(Qt5DBus)
> add_definitions(-DQT_NO_KEYWORDS)
>
> -check_include_file_cxx("waudio.h" USE_AUDIOFLINGER)
> -if (USE_AUDIOFLINGER)
> - add_definitions(-DUSE_AUDIOFLINGER)
> - set(WAUDIO_LIBRARIES -lwaudio)
> -endif (USE_AUDIOFLINGER)
> -
> find_package(PkgConfig REQUIRED)
> pkg_check_modules(TP_QT5 REQUIRED TelepathyQt5)
> pkg_check_modules(SQLITE3 REQUIRED sqlite3)
>
> === modified file 'connection.cpp'
> --- connection.cpp 2014-07-25 21:29:26 +0000
> +++ connection.cpp 2014-08-04 01:52:16 +0000
> @@ -34,10 +34,6 @@
>
> #include "mmsdmessage.h"
> #include "mmsdservice.h"
> -// audioflinger
> -#ifdef USE_AUDIOFLINGER
> -#include <waudio.h>
> -#endif
>
> #ifdef USE_PULSEAUDIO
> #include "qpulseaudioengine.h"
> @@ -48,84 +44,30 @@
>
> static void enable_earpiece()
> {
> -#ifdef USE_AUDIOFLINGER
> - char parameter[20];
> - int i;
> - /* Set the call mode in AudioFlinger */
> - AudioSystem_setMode(AUDIO_MODE_IN_CALL);
> - sprintf(parameter, "routing=%d", AUDIO_DEVICE_OUT_EARPIECE);
> - /* Try the first 3 threads, as this is not fixed and there's no easy
> - * way to retrieve the default thread/output from Android */
> - for (i = 1; i <= 3; i++) {
> - if (AudioSystem_setParameters(i, parameter) >= 0)
> - break;
> - }
> -#endif
> #ifdef USE_PULSEAUDIO
> - QPulseAudioEngine::instance()->setCallMode(true, false);
> + QPulseAudioEngine::instance()->setCallMode(QPulseAudioEngine::CallActive, QPulseAudioEngine::CallNormal);
> #endif
> }
>
> static void enable_normal()
> {
> -#ifdef USE_AUDIOFLINGER
> - char parameter[20];
> - int i;
> - /* Set normal mode in AudioFlinger */
> - AudioSystem_setMode(AUDIO_MODE_NORMAL);
> - /* Get device back to speaker mode, as by default in_call
> - * mode sets up device out to earpiece */
> - sprintf(parameter, "routing=%d", AUDIO_DEVICE_OUT_SPEAKER);
> - /* Try the first 3 threads, as this is not fixed and there's no easy
> - * way to retrieve the default thread/output from Android */
> - for (i = 1; i <= 3; i++) {
> - if (AudioSystem_setParameters(i, parameter) >= 0)
> - break;
> - }
> -#endif
> #ifdef USE_PULSEAUDIO
> - QPulseAudioEngine::instance()->setCallMode(false, false);
> + QPulseAudioEngine::instance()->setCallMode(QPulseAudioEngine::CallEnded, QPulseAudioEngine::CallNormal);
> QPulseAudioEngine::instance()->setMicMute(false);
> #endif
> }
>
> static void enable_speaker()
> {
> -#ifdef USE_AUDIOFLINGER
> - char parameter[20];
> - int i;
> - /* Set the call mode in AudioFlinger */
> - AudioSystem_setMode(AUDIO_MODE_IN_CALL);
> - sprintf(parameter, "routing=%d", AUDIO_DEVICE_OUT_SPEAKER);
> - /* Try the first 3 threads, as this is not fixed and there's no easy
> - * way to retrieve the default thread/output from Android */
> - for (i = 1; i <= 3; i++) {
> - if (AudioSystem_setParameters(i, parameter) >= 0)
> - break;
> - }
> -#endif
> #ifdef USE_PULSEAUDIO
> - QPulseAudioEngine::instance()->setCallMode(true, true);
> + QPulseAudioEngine::instance()->setCallMode(QPulseAudioEngine::CallActive, QPulseAudioEngine::CallSpeaker);
> #endif
> }
>
> static void enable_ringtone()
> {
> -#ifdef USE_AUDIOFLINGER
> - char parameter[20];
> - int i;
> - /* Set the call mode in AudioFlinger */
> - AudioSystem_setMode(AUDIO_MODE_IN_CALL);
> - sprintf(parameter, "routing=%d", AUDIO_DEVICE_OUT_SPEAKER);
> - /* Try the first 3 threads, as this is not fixed and there's no easy
> - * way to retrieve the default thread/output from Android */
> - for (i = 1; i <= 3; i++) {
> - if (AudioSystem_setParameters(i, parameter) >= 0)
> - break;
> - }
> -#endif
> #ifdef USE_PULSEAUDIO
> - QPulseAudioEngine::instance()->setCallMode(false, true);
> + QPulseAudioEngine::instance()->setCallMode(QPulseAudioEngine::CallRinging, QPulseAudioEngine::CallNormal);
> #endif
> }
>
>
> === modified file 'qpulseaudioengine.cpp'
> --- qpulseaudioengine.cpp 2014-06-26 17:35:25 +0000
> +++ qpulseaudioengine.cpp 2014-08-04 01:52:16 +0000
> @@ -23,14 +23,14 @@
> #include <sys/types.h>
> #include <unistd.h>
>
> +#define PULSEAUDIO_PROFILE_HSP "hsp"
> +#define PULSEAUDIO_PROFILE_A2DP "a2dp"
> +
> QT_BEGIN_NAMESPACE
>
> static void contextStateCallbackInit(pa_context *context, void *userdata)
> {
> Q_UNUSED(context);
> -#ifdef DEBUG_PULSE
> - qDebug() << QPulseAudioInternal::stateToQString(pa_context_get_state(context));
> -#endif
> QPulseAudioEngine *pulseEngine = reinterpret_cast<QPulseAudioEngine*>(userdata);
> pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
> }
> @@ -39,11 +39,6 @@
> {
> Q_UNUSED(userdata);
> Q_UNUSED(context);
> -
> -#ifdef DEBUG_PULSE
> - pa_context_state_t state = pa_context_get_state(context);
> - qDebug() << QPulseAudioInternal::stateToQString(state);
> -#endif
> }
>
> static void success_cb(pa_context *context, int success, void *userdata)
> @@ -54,14 +49,18 @@
>
> static void subscribeCallback(pa_context *context, pa_subscription_event_type_t t, uint32_t idx, void *userdata)
> {
> - /* We're interested in plug/unplug stuff only, i e, card changes */
> - if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) != PA_SUBSCRIPTION_EVENT_CARD)
> - return;
> - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
> - return;
> -
> - /* Handle it later, and in the right thread */
> - QMetaObject::invokeMethod((QPulseAudioEngine *) userdata, "plugUnplugSlot", Qt::QueuedConnection);
> + /* For card change events (slot plug/unplug and add/remove card) */
> + if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_CARD) {
> + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE)
> + QMetaObject::invokeMethod((QPulseAudioEngine *) userdata, "plugUnplugSlot", Qt::QueuedConnection);
> + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW)
> + QMetaObject::invokeMethod((QPulseAudioEngine *) userdata, "plugUnplugCard", Qt::QueuedConnection);
> + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
> + /* unplug slot is needed because remove gets called after event change */
> + QMetaObject::invokeMethod((QPulseAudioEngine *) userdata, "plugUnplugCard", Qt::QueuedConnection);
> + QMetaObject::invokeMethod((QPulseAudioEngine *) userdata, "plugUnplugSlot", Qt::QueuedConnection);
> + }
> + }
> }
>
> Q_GLOBAL_STATIC(QPulseAudioEngine, pulseEngine);
> @@ -70,9 +69,16 @@
> : QObject(parent)
> , m_mainLoopApi(0)
> , m_context(0)
> - , m_incall(false)
> - , m_speakermode(false)
> + , m_callstatus(CallEnded)
> + , m_callmode(CallNormal)
> , m_micmute(false)
> + , m_defaultsink("sink.primary")
> + , m_defaultsource("source.primary")
> + , m_voicecallcard("")
> + , m_voicecallhighest("")
> + , m_voicecallprofile("")
> + , m_bt_hsp("")
> + , m_bt_hsp_a2dp("")
>
> {
> bool keepGoing = true;
> @@ -120,21 +126,19 @@
> break;
>
> case PA_CONTEXT_READY:
> -#ifdef DEBUG_PULSE
> - qDebug("Connection established.");
> -#endif
> + qDebug("Pulseaudio connection established.");
> keepGoing = false;
> break;
>
> case PA_CONTEXT_TERMINATED:
> - qCritical("Context terminated.");
> + qCritical("Pulseaudio context terminated.");
> keepGoing = false;
> ok = false;
> break;
>
> case PA_CONTEXT_FAILED:
> default:
> - qCritical() << QString("Connection failure: %1").arg(pa_strerror(pa_context_errno(m_context)));
> + qCritical() << QString("Pulseaudio connection failure: %1").arg(pa_strerror(pa_context_errno(m_context)));
> keepGoing = false;
> ok = false;
> }
> @@ -179,103 +183,125 @@
> return pulseEngine();
> }
>
> +void QPulseAudioEngine::cardInfoCallback(const pa_card_info *info)
> +{
> + pa_card_profile_info *voice_call = NULL, *highest = NULL;
> + pa_card_profile_info *hsp = NULL, *a2dp = NULL;
> +
> + /* For now we only support one card with the voicecall feature */
> + for (int i = 0; i < info->n_profiles; i++) {
> + if (!highest || info->profiles[i].priority > highest->priority)
> + highest = &info->profiles[i];
> + if (!strcmp(info->profiles[i].name, "voicecall"))
Not sure if the compiler is smart enough to optimize this, but can we use "else if ()" in the last three "if" statements?
> + voice_call = &info->profiles[i];
> + if (!strcmp(info->profiles[i].name, PULSEAUDIO_PROFILE_HSP))
> + hsp = &info->profiles[i];
> + if (!strcmp(info->profiles[i].name, PULSEAUDIO_PROFILE_A2DP))
> + a2dp = &info->profiles[i];
> + }
> +
> + /* Record the card that supports voicecall (default one to be used) */
> + if (voice_call) {
> + qDebug("Found card that supports voicecall: '%s'", info->name);
> + m_voicecallcard = info->name;
> + m_voicecallhighest = highest->name;
> + m_voicecallprofile = voice_call->name;
> + }
> +
> + /* Handle the use cases needed for bluetooth */
> + if (hsp && a2dp) {
> + qDebug("Found card that supports hsp and a2dp: '%s'", info->name);
> + m_bt_hsp_a2dp = info->name;
> + } else if (hsp && (a2dp == NULL)) {
> + /* This card only provides the hsp profile */
> + qDebug("Found card that supports only hsp: '%s'", info->name);
> + m_bt_hsp = info->name;
> + }
> +}
> +
> void QPulseAudioEngine::sinkInfoCallback(const pa_sink_info *info)
> {
> - pa_sink_port_info *earpiece = NULL, *speaker = NULL, *headphones = NULL;
> + pa_sink_port_info *earpiece = NULL, *speaker = NULL;
> pa_sink_port_info *highest = NULL, *preferred = NULL;
> + pa_sink_port_info *bluetooth_sco = NULL;
>
> for (int i = 0; i < info->n_ports; i++) {
> - if (!highest || info->ports[i]->priority > highest->priority) {
> + if (!highest || info->ports[i]->priority > highest->priority)
> if (info->ports[i]->available != PA_PORT_AVAILABLE_NO)
> highest = info->ports[i];
> - }
> if (!strcmp(info->ports[i]->name, "output-earpiece"))
same here
> earpiece = info->ports[i];
> if (!strcmp(info->ports[i]->name, "output-speaker"))
> speaker = info->ports[i];
> - if (!strcmp(info->ports[i]->name, "output-wired_headset") && info->ports[i]->available != PA_PORT_AVAILABLE_NO)
> - headphones = info->ports[i];
> - if (!strcmp(info->ports[i]->name, "output-wired_headphone") && info->ports[i]->available != PA_PORT_AVAILABLE_NO)
> - headphones = info->ports[i];
> + if (!strcmp(info->ports[i]->name, "output-bluetooth_sco"))
> + bluetooth_sco = info->ports[i];
> }
>
> if (!earpiece)
> return; /* Not the right sink */
>
> - /* TODO: When on ringtone and headphones are plugged in, people want output
> - through *both* headphones and speaker, but when on call with speaker mode,
> - people want *just* speaker, not including headphones. */
> - if (m_speakermode)
> + if (m_callmode == CallSpeaker)
> preferred = speaker;
> - else if (m_incall)
> - preferred = headphones ? headphones : earpiece;
> + else if (m_callstatus == CallActive) {
> + if (bluetooth_sco && ((m_bt_hsp != "") || (m_bt_hsp_a2dp != "")))
> + preferred = bluetooth_sco;
> + else if (highest == speaker)
> + preferred = earpiece;
> + else
> + preferred = highest;
> + }
> +
> if (!preferred)
> preferred = highest;
>
> - if (preferred && preferred != info->active_port) {
> - m_nametoset = info->name;
> - m_valuetoset = preferred->name;
> - }
> -}
> -
> -void QPulseAudioEngine::cardInfoCallback(const pa_card_info *info)
> -{
> - pa_card_profile_info *voice_call = NULL, *highest = NULL;
> -
> - for (int i = 0; i < info->n_profiles; i++) {
> - if (!highest || info->profiles[i].priority > highest->priority)
> - highest = &info->profiles[i];
> - if (!strcmp(info->profiles[i].name, "voicecall"))
> - voice_call = &info->profiles[i];
> - }
> -
> - if (!voice_call)
> - return; /* Not the right card */
> -
> - if (m_incall && (voice_call != info->active_profile)) {
> - m_nametoset = info->name;
> - m_valuetoset = voice_call->name;
> - }
> - else if (!m_incall && (voice_call == info->active_profile)) {
> - m_nametoset = info->name;
> - m_valuetoset = highest->name;
> - }
> + m_nametoset = info->name;
> + if (info->active_port != preferred)
> + m_valuetoset = preferred->name;
> }
>
> void QPulseAudioEngine::sourceInfoCallback(const pa_source_info *info)
> {
> - pa_source_port_info *builtin_mic = NULL, *headset = NULL;
> + pa_source_port_info *builtin_mic = NULL, *highest = NULL;
> pa_source_port_info *preferred = NULL;
>
> if (info->monitor_of_sink != PA_INVALID_INDEX)
> return; /* Not the right source */
>
> for (int i = 0; i < info->n_ports; i++) {
> + if (!highest || info->ports[i]->priority > highest->priority)
> + if (info->ports[i]->available != PA_PORT_AVAILABLE_NO)
> + highest = info->ports[i];
> if (!strcmp(info->ports[i]->name, "input-builtin_mic"))
> builtin_mic = info->ports[i];
> - if (!strcmp(info->ports[i]->name, "input-wired_headset") && info->ports[i]->available != PA_PORT_AVAILABLE_NO)
> - headset = info->ports[i];
> }
>
> if (!builtin_mic)
> return; /* Not the right source */
>
> - preferred = headset ? headset : builtin_mic;
> -
> - if (preferred && preferred != info->active_port) {
> - m_nametoset = info->name;
> + if (m_callmode == CallSpeaker)
> + preferred = builtin_mic;
> +
> + if (!preferred)
> + preferred = highest;
> +
> + m_nametoset = info->name;
> + if (info->active_port != preferred)
> m_valuetoset = preferred->name;
> - }
> -
> - if (!!info->mute != !!m_micmute) {
> - m_nametoset = info->name;
> - }
> +}
> +
> +void QPulseAudioEngine::serverInfoCallback(const pa_server_info *info)
> +{
> + /* Saving default sink/source to restore after call hangup */
> + m_defaultsink = info->default_sink_name;
> + m_defaultsource = info->default_source_name;
> +
> + /* In the case of a server callback we need to signal the mainloop */
> + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
> }
>
> static void cardinfo_cb(pa_context *context, const pa_card_info *info, int isLast, void *userdata)
> {
> QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
> -/* qDebug("cardinfo_cb: pulseengine = %p, info = %p, isLast = %d", pulseEngine, info, isLast); */
> if (isLast != 0 || !pulseEngine || !info) {
> pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
> return;
> @@ -303,10 +329,20 @@
> pulseEngine->sourceInfoCallback(info);
> }
>
> +static void serverinfo_cb(pa_context *context, const pa_server_info *info, void *userdata)
> +{
> + QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
> + if (!pulseEngine || !info) {
> + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
> + return;
> + }
> + pulseEngine->serverInfoCallback(info);
> +}
> +
> bool QPulseAudioEngine::handleOperation(pa_operation *operation, const char *func_name)
> {
> if (!operation) {
> - qDebug("'%s' failed (lost PulseAudio connection?)", func_name);
> + qCritical("'%s' failed (lost PulseAudio connection?)", func_name);
> pa_threaded_mainloop_unlock(m_mainLoop);
> return false;
> }
> @@ -317,70 +353,178 @@
> return true;
> }
>
> -void QPulseAudioEngine::setCallMode(bool inCall, bool speakerMode)
> +void QPulseAudioEngine::setupVoiceCall()
> {
> - pa_operation *operation;
> + pa_operation *o;
>
> - m_incall = inCall;
> - m_speakermode = speakerMode;
> + qDebug("Setting up pulseaudio for voice call");
>
> pa_threaded_mainloop_lock(m_mainLoop);
>
> - m_nametoset = "";
> - pa_operation *o = pa_context_get_card_info_list(m_context, cardinfo_cb, this);
> + /* Get and set the default sink/source to be restored later */
> + o = pa_context_get_server_info(m_context, serverinfo_cb, this);
> + if (!handleOperation(o, "pa_context_get_server_info"))
> + return;
> +
> + qDebug("Recorded default sink: %s default source: %s",
> + m_defaultsink.c_str(), m_defaultsource.c_str());
> +
> + /* Walk through the list of devices, find the voice call capable card and
> + * identify if we have bluetooth capable devices (hsp and a2dp) */
> + m_voicecallcard = m_voicecallhighest = m_voicecallprofile = "";
> + m_bt_hsp = m_bt_hsp_a2dp = "";
> + o = pa_context_get_card_info_list(m_context, cardinfo_cb, this);
> if (!handleOperation(o, "pa_context_get_card_info_list"))
> return;
> -
> - if (m_nametoset != "") {
> - qDebug("Setting PulseAudio card '%s' profile '%s'", m_nametoset.c_str(), m_valuetoset.c_str());
> - o = pa_context_set_card_profile_by_name(m_context,
> - m_nametoset.c_str(), m_valuetoset.c_str(), success_cb, this);
> - if (!handleOperation(o, "pa_context_set_card_profile_by_name"))
> - return;
> - }
> -
> - m_nametoset = "";
> + /* In case we have only one bt device that provides hsp and a2dp, we need
> + * to make sure we switch the default profile for that card (to hsp) */
> + if ((m_bt_hsp_a2dp != "") && (m_bt_hsp == "")) {
> + qDebug("Setting PulseAudio card '%s' profile '%s'",
> + m_bt_hsp_a2dp.c_str(), PULSEAUDIO_PROFILE_HSP);
> + o = pa_context_set_card_profile_by_name(m_context,
> + m_bt_hsp_a2dp.c_str(), PULSEAUDIO_PROFILE_HSP, success_cb, this);
> + if (!handleOperation(o, "pa_context_set_card_profile_by_name"))
> + return;
> + }
> +
> + pa_threaded_mainloop_unlock(m_mainLoop);
> +}
> +
> +void QPulseAudioEngine::restoreVoiceCall()
> +{
> + pa_operation *o;
> +
> + qDebug("Restoring pulseaudio previous state");
> +
> + /* Then restore previous settings */
> + pa_threaded_mainloop_lock(m_mainLoop);
> +
> + /* See if we need to restore any HSP+AD2P device state */
> + if ((m_bt_hsp_a2dp != "") && (m_bt_hsp == "")) {
> + qDebug("Restoring PulseAudio card '%s' to profile '%s'",
> + m_bt_hsp_a2dp.c_str(), PULSEAUDIO_PROFILE_A2DP);
> + o = pa_context_set_card_profile_by_name(m_context,
> + m_bt_hsp_a2dp.c_str(), PULSEAUDIO_PROFILE_A2DP, success_cb, this);
> + if (!handleOperation(o, "pa_context_set_card_profile_by_name"))
> + return;
> + }
> +
> + /* Restore default sink/source */
> + if (m_defaultsink != "") {
> + qDebug("Restoring PulseAudio default sink to '%s'", m_defaultsink.c_str());
> + o = pa_context_set_default_sink(m_context, m_defaultsink.c_str(), success_cb, this);
> + if (!handleOperation(o, "pa_context_set_default_sink"))
> + return;
> + }
> + if (m_defaultsource != "") {
> + qDebug("Restoring PulseAudio default source to '%s'", m_defaultsource.c_str());
> + o = pa_context_set_default_source(m_context, m_defaultsource.c_str(), success_cb, this);
> + if (!handleOperation(o, "pa_context_set_default_source"))
> + return;
> + }
> +
> + pa_threaded_mainloop_unlock(m_mainLoop);
> +}
> +
> +void QPulseAudioEngine::setCallMode(QPulseAudioEngine::CallStatus callstatus, QPulseAudioEngine::CallMode callmode)
> +{
> + pa_operation *o;
> +
> + /* Check if we need to save the current pulseaudio state (e.g. when starting a call) */
> + if ((callstatus != CallEnded) && (m_callstatus == CallEnded)) {
> + setupVoiceCall();
> + }
> +
> + /* If we have an active call, update internal state (used later when updating sink/source ports */
> + m_callstatus = callstatus;
> + m_callmode = callmode;
> +
> + /* Switch the virtual card mode when call is active and not active
> + * This needs to be done before sink/source gets updated, because after changing mode
> + * it will automatically move to input/output-parking */
> + if ((m_callstatus == CallActive) && (m_voicecallcard != "") && (m_voicecallprofile != "")) {
> + qDebug("Setting PulseAudio card '%s' profile '%s'",
> + m_voicecallcard.c_str(), m_voicecallprofile.c_str());
> + o = pa_context_set_card_profile_by_name(m_context,
> + m_voicecallcard.c_str(), m_voicecallprofile.c_str(), success_cb, this);
> + if (!handleOperation(o, "pa_context_set_card_profile_by_name"))
> + return;
> + } else if ((m_callstatus == CallEnded) && (m_voicecallcard != "") && (m_voicecallhighest != "")) {
> + /* If using droid, make sure to restore to the profile that has the highest score */
> + qDebug("Restoring PulseAudio card '%s' to profile '%s'",
> + m_voicecallcard.c_str(), m_voicecallhighest.c_str());
> + o = pa_context_set_card_profile_by_name(m_context,
> + m_voicecallcard.c_str(), m_voicecallhighest.c_str(), success_cb, this);
> + if (!handleOperation(o, "pa_context_set_card_profile_by_name"))
> + return;
> + }
> +
> + /* Update sink/source ports */
> + pa_threaded_mainloop_lock(m_mainLoop);
> +
> + /* Find highest compatible sink/source elements from the voicecall
> + compatible card (on touch this means the pulse droid element) */
> + m_nametoset = m_valuetoset = "";
> o = pa_context_get_sink_info_list(m_context, sinkinfo_cb, this);
> if (!handleOperation(o, "pa_context_get_sink_info_list"))
> return;
> -
> - if (m_nametoset != "") {
> - qDebug("Setting PulseAudio sink '%s' port '%s'", m_nametoset.c_str(), m_valuetoset.c_str());
> - o = pa_context_set_sink_port_by_name(m_context,
> - m_nametoset.c_str(), m_valuetoset.c_str(), success_cb, this);
> + if ((m_nametoset != "") && (m_nametoset != m_defaultsink)) {
> + qDebug("Setting PulseAudio default sink to '%s'", m_nametoset.c_str());
> + o = pa_context_set_default_sink(m_context, m_nametoset.c_str(), success_cb, this);
> + if (!handleOperation(o, "pa_context_set_default_sink"))
> + return;
> + }
> + if (m_valuetoset != "") {
> + qDebug("Setting PulseAudio sink '%s' port '%s'",
> + m_nametoset.c_str(), m_valuetoset.c_str());
> + o = pa_context_set_sink_port_by_name(m_context, m_nametoset.c_str(),
> + m_valuetoset.c_str(), success_cb, this);
> if (!handleOperation(o, "pa_context_set_sink_port_by_name"))
> return;
> }
>
> - m_nametoset = "";
> + /* Same for source */
> + m_nametoset = m_valuetoset = "";
> o = pa_context_get_source_info_list(m_context, sourceinfo_cb, this);
> if (!handleOperation(o, "pa_context_get_source_info_list"))
> return;
> -
> - if (m_nametoset != "") {
> - qDebug("Setting PulseAudio source '%s' port '%s'", m_nametoset.c_str(), m_valuetoset.c_str());
> - o = pa_context_set_source_port_by_name(m_context,
> - m_nametoset.c_str(), m_valuetoset.c_str(), success_cb, this);
> + if ((m_nametoset != "") && (m_nametoset != m_defaultsource)) {
> + qDebug("Setting PulseAudio default source to '%s'", m_nametoset.c_str());
> + o = pa_context_set_default_source(m_context, m_nametoset.c_str(), success_cb, this);
> + if (!handleOperation(o, "pa_context_set_default_source"))
> + return;
> + }
> + if (m_valuetoset != "") {
> + qDebug("Setting PulseAudio source '%s' port '%s'",
> + m_nametoset.c_str(), m_valuetoset.c_str());
> + o = pa_context_set_source_port_by_name(m_context, m_nametoset.c_str(),
> + m_valuetoset.c_str(), success_cb, this);
> if (!handleOperation(o, "pa_context_set_source_port_by_name"))
> return;
> }
>
> pa_threaded_mainloop_unlock(m_mainLoop);
>
> - if (inCall)
> + /* If no more active voicecall, restore previous saved pulseaudio state */
> + if (callstatus == CallEnded) {
> + restoreVoiceCall();
> + }
> +
> + /* In case the app had set mute when the call wasn't active, make sure we reflect it here */
> + if (m_callstatus != CallEnded)
> setMicMute(m_micmute);
> }
>
> void QPulseAudioEngine::setMicMute(bool muted)
> {
> - m_nametoset = "";
> m_micmute = muted;
>
> - if (!m_incall)
> + if (m_callstatus == CallEnded)
> return;
>
> pa_threaded_mainloop_lock(m_mainLoop);
>
> + m_nametoset = "";
> pa_operation *o = pa_context_get_source_info_list(m_context, sourceinfo_cb, this);
> if (!handleOperation(o, "pa_context_get_source_info_list"))
> return;
> @@ -397,11 +541,20 @@
> pa_threaded_mainloop_unlock(m_mainLoop);
> }
>
> +void QPulseAudioEngine::plugUnplugCard()
> +{
> + qDebug("Notified about card add/removed event from PulseAudio");
> +
> + if (m_callstatus != CallEnded)
> + setupVoiceCall();
> +}
> +
> void QPulseAudioEngine::plugUnplugSlot()
> {
> - qDebug("Notified about card event from PulseAudio");
> - if (m_incall)
> - setCallMode(m_incall, m_speakermode);
> + qDebug("Notified about card changes (port) event from PulseAudio");
> +
> + if (m_callstatus == CallActive)
> + setCallMode(m_callstatus, m_callmode);
> }
>
> QT_END_NAMESPACE
>
> === modified file 'qpulseaudioengine.h'
> --- qpulseaudioengine.h 2013-11-06 14:08:47 +0000
> +++ qpulseaudioengine.h 2014-08-04 01:52:16 +0000
> @@ -31,6 +31,18 @@
> Q_OBJECT
>
> public:
> + enum CallStatus {
> + CallRinging,
> + CallActive,
> + CallEnded
> + };
> +
> + enum CallMode {
> + CallNormal,
> + CallSpeaker,
> + CallBluetooth
> + };
> +
> QPulseAudioEngine(QObject *parent = 0);
> ~QPulseAudioEngine();
>
> @@ -38,22 +50,31 @@
> pa_threaded_mainloop *mainloop() { return m_mainLoop; }
> pa_context *context() { return m_context; }
>
> - void setCallMode(bool inCall, bool speakerMode);
> + void setupVoiceCall(void);
> + void restoreVoiceCall(void);
> + void setCallMode(CallStatus callstatus, CallMode callmode);
> void setMicMute(bool muted); /* True if muted, false if unmuted */
>
> /* These four are only used internally */
> void cardInfoCallback(const pa_card_info *card);
> void sinkInfoCallback(const pa_sink_info *sink);
> void sourceInfoCallback(const pa_source_info *source);
> + void serverInfoCallback(const pa_server_info *server);
> public Q_SLOTS:
> + void plugUnplugCard();
> void plugUnplugSlot();
> private:
> pa_mainloop_api *m_mainLoopApi;
> pa_threaded_mainloop *m_mainLoop;
> pa_context *m_context;
>
> - bool m_incall, m_speakermode, m_micmute;
> + CallStatus m_callstatus;
> + CallMode m_callmode;
> + bool m_micmute;
> std::string m_nametoset, m_valuetoset;
> + std::string m_defaultsink, m_defaultsource;
> + std::string m_bt_hsp, m_bt_hsp_a2dp;
> + std::string m_voicecallcard, m_voicecallhighest, m_voicecallprofile;
>
> bool handleOperation(pa_operation *operation, const char *func_name);
> };
>
--
https://code.launchpad.net/~rsalveti/telepathy-ofono/adding_support_for_hsp/+merge/229292
Your team Ubuntu Phablet Team is requested to review the proposed merge of lp:~rsalveti/telepathy-ofono/adding_support_for_hsp into lp:telepathy-ofono.
More information about the Ubuntu-reviews
mailing list