[Merge] lp:~justinmcp/media-hub/1239432 into lp:media-hub

Jim Hodapp jim.hodapp at canonical.com
Tue Nov 4 23:33:54 UTC 2014


Review: Needs Fixing code

Looks really good. Only one minor inline comment to address. Would like to help you test it after you get it built in a silo.

Diff comments:

> === modified file 'CMakeLists.txt'
> --- CMakeLists.txt	2014-10-14 16:21:47 +0000
> +++ CMakeLists.txt	2014-11-03 00:57:41 +0000
> @@ -6,8 +6,8 @@
>  set(UBUNTU_MEDIA_HUB_VERSION_MINOR 0)
>  set(UBUNTU_MEDIA_HUB_VERSION_PATCH 0)
>  
> -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wall -pedantic -Wextra -fPIC -pthread")
> -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -fno-strict-aliasing -pedantic -Wextra -fPIC -pthread")
> +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fPIC -pthread")
> +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -fno-strict-aliasing -Wextra -fPIC -pthread")
>  
>  set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
>  
> 
> === modified file 'debian/control'
> --- debian/control	2014-10-23 21:25:38 +0000
> +++ debian/control	2014-11-03 00:57:41 +0000
> @@ -28,6 +28,8 @@
>                 gstreamer1.0-libav,
>                 libgstreamer1.0-dev,
>                 pkg-config,
> +               qtbase5-dev,
> +               libtelepathy-qt5-dev,
>  Standards-Version: 3.9.5
>  Homepage: https://launchpad.net/media-hub
>  # If you aren't a member of ~phablet-team but need to upload packaging changes,
> 
> === modified file 'src/core/media/CMakeLists.txt'
> --- src/core/media/CMakeLists.txt	2014-10-14 16:21:47 +0000
> +++ src/core/media/CMakeLists.txt	2014-11-03 00:57:41 +0000
> @@ -7,6 +7,8 @@
>  
>  file(GLOB MPRIS_HEADERS mpris/ *.h)
>  
> +add_subdirectory(call-monitor)
> +
>  add_library(
>    media-hub-common SHARED
>  
> @@ -90,7 +92,7 @@
>    media-hub-service
>  
>    media-hub-common
> -
> +  call-monitor
>    ${DBUS_LIBRARIES}
>    ${DBUS_CPP_LDFLAGS}
>    ${GLog_LIBRARY}
> @@ -113,6 +115,7 @@
>  
>    media-hub-service
>    media-hub-client
> +  call-monitor
>  
>    ${DBUS_LIBRARIES}
>    ${DBUS_CPP_LDFLAGS}
> 
> === added directory 'src/core/media/call-monitor'
> === added file 'src/core/media/call-monitor/CMakeLists.txt'
> --- src/core/media/call-monitor/CMakeLists.txt	1970-01-01 00:00:00 +0000
> +++ src/core/media/call-monitor/CMakeLists.txt	2014-11-03 00:57:41 +0000
> @@ -0,0 +1,23 @@
> +SET (CMAKE_INCLUDE_CURRENT_DIR ON)
> +SET (CMAKE_AUTOMOC ON)
> +
> +find_package(Qt5Core REQUIRED)
> +find_package(PkgConfig REQUIRED)
> +pkg_check_modules(TP_QT5 REQUIRED TelepathyQt5)
> +
> +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -Wextra -fPIC -pthread")
> +
> +include_directories(
> +    ${TP_QT5_INCLUDE_DIRS}
> +)
> +
> +add_library(call-monitor STATIC
> +    call_monitor.cpp
> +    qtbridge.cpp
> +)
> +
> +target_link_libraries(call-monitor
> +    ${TP_QT5_LIBRARIES}
> +)
> +
> +qt5_use_modules(call-monitor Core DBus)
> 
> === added file 'src/core/media/call-monitor/call_monitor.cpp'
> --- src/core/media/call-monitor/call_monitor.cpp	1970-01-01 00:00:00 +0000
> +++ src/core/media/call-monitor/call_monitor.cpp	2014-11-03 00:57:41 +0000
> @@ -0,0 +1,207 @@
> +/*
> + * Copyright (C) 2014 Canonical Ltd
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License version 3 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + *      Author: Justin McPherson <justin.mcpherson at canonical.com>
> + */
> +
> +
> +#include "call_monitor.h"
> +
> +#include "qtbridge.h"
> +#include <TelepathyQt/AccountManager>
> +#include <TelepathyQt/SimpleCallObserver>
> +#include <TelepathyQt/PendingOperation>
> +#include <TelepathyQt/PendingReady>
> +#include <TelepathyQt/PendingAccount>
> +
> +#include <list>
> +#include <mutex>
> +#include <syslog.h>

I didn't see anything that would require this include. Is it really necessary?

> +
> +
> +namespace {
> +class TelepathyCallMonitor : public QObject
> +{
> +    Q_OBJECT
> +public:
> +    TelepathyCallMonitor(const Tp::AccountPtr& account):
> +        mAccount(account),
> +        mCallObserver(Tp::SimpleCallObserver::create(mAccount)) {
> +        connect(mCallObserver.data(), SIGNAL(callStarted(Tp::CallChannelPtr)), SIGNAL(offHook()));
> +        connect(mCallObserver.data(), SIGNAL(callEnded(Tp::CallChannelPtr,QString,QString)), SIGNAL(onHook()));
> +        connect(mCallObserver.data(), SIGNAL(streamedMediaCallStarted(Tp::StreamedMediaChannelPtr)), SIGNAL(offHook()));
> +        connect(mCallObserver.data(), SIGNAL(streamedMediaCallEnded(Tp::StreamedMediaChannelPtr,QString,QString)), SIGNAL(onHook()));
> +    }
> +
> +Q_SIGNALS:
> +    void offHook();
> +    void onHook();
> +
> +private:
> +    Tp::AccountPtr mAccount;
> +    Tp::SimpleCallObserverPtr mCallObserver;
> +};
> +
> +
> +class TelepathyBridge : public QObject
> +{
> +    Q_OBJECT
> +public:
> +    TelepathyBridge():
> +        QObject(0) {
> +        Tp::registerTypes();
> +
> +        QTimer::singleShot(0, this, SLOT(accountManagerSetup()));
> +    }
> +
> +    ~TelepathyBridge() {
> +        for (std::list<TelepathyCallMonitor*>::iterator it = mCallMonitors.begin();
> +            it != mCallMonitors.end();
> +            ++it) {
> +            delete *it;
> +        }
> +    }
> +
> +    void on_change(const std::function<void(CallMonitor::State)>& func) {
> +        std::lock_guard<std::mutex> l(cb_lock);
> +        cb = func;
> +    }
> +
> +private Q_SLOTS:
> +    void accountManagerSetup() {
> +        mAccountManager = Tp::AccountManager::create();
> +        connect(mAccountManager->becomeReady(),
> +                SIGNAL(finished(Tp::PendingOperation*)),
> +                SLOT(accountManagerReady(Tp::PendingOperation*)));
> +    }
> +
> +    void accountManagerReady(Tp::PendingOperation* operation) {
> +        if (operation->isError()) {
> +            std::cerr << "TelepathyBridge: Operation failed (accountManagerReady)" << std::endl;
> +            QTimer::singleShot(1000, this, SLOT(accountManagerSetup())); // again
> +            return;
> +        }
> +
> +        Q_FOREACH(const Tp::AccountPtr& account, mAccountManager->allAccounts()) {
> +            connect(account->becomeReady(Tp::Account::FeatureCapabilities),
> +                    SIGNAL(finished(Tp::PendingOperation*)),
> +                    SLOT(accountReady(Tp::PendingOperation*)));
> +        }
> +
> +        connect(mAccountManager.data(), SIGNAL(newAccount(Tp::AccountPtr)), SLOT(newAccount(Tp::AccountPtr)));
> +    }
> +
> +    void newAccount(const Tp::AccountPtr& account)
> +    {
> +        connect(account->becomeReady(Tp::Account::FeatureCapabilities),
> +                SIGNAL(finished(Tp::PendingOperation*)),
> +                SLOT(accountReady(Tp::PendingOperation*)));
> +    }
> +
> +    void accountReady(Tp::PendingOperation* operation) {
> +        if (operation->isError()) {
> +            std::cerr << "TelepathyAccount: Operation failed (accountReady)" << std::endl;
> +            return;
> +        }
> +
> +        Tp::PendingReady* pendingReady = qobject_cast<Tp::PendingReady*>(operation);
> +        if (pendingReady == 0) {
> +            std::cerr << "Rejecting account because could not understand ready status" << std::endl;
> +            return;
> +        }
> +
> +        checkAndAddAccount(Tp::AccountPtr::qObjectCast(pendingReady->proxy()));
> +    }
> +
> +    void offHook()
> +    {
> +        std::lock_guard<std::mutex> l(cb_lock);
> +        if (cb)
> +            cb(CallMonitor::OffHook);
> +    }
> +
> +    void onHook()
> +    {
> +        std::lock_guard<std::mutex> l(cb_lock);
> +        if (cb)
> +            cb(CallMonitor::OnHook);
> +    }
> +
> +private:
> +    std::mutex cb_lock;
> +    std::function<void (CallMonitor::State)>   cb;
> +    Tp::AccountManagerPtr mAccountManager;
> +    std::list<TelepathyCallMonitor*> mCallMonitors;
> +
> +    void checkAndAddAccount(const Tp::AccountPtr& account)
> +    {
> +        Tp::ConnectionCapabilities caps = account->capabilities();
> +
> +        // anything call like, perhaps overkill?
> +        if (caps.audioCalls() || caps.videoCalls() || caps.videoCallsWithAudio() || caps.streamedMediaCalls()) {
> +            auto tcm = new TelepathyCallMonitor(account);
> +            connect(tcm, SIGNAL(offHook()), SLOT(offHook()));
> +            connect(tcm, SIGNAL(onHook()), SLOT(onHook()));
> +            mCallMonitors.push_back(tcm);
> +        }
> +    }
> +};
> +}
> +
> +class CallMonitorPrivate
> +{
> +public:
> +    CallMonitorPrivate() {
> +        try {
> +            std::thread([this]() {
> +                qt::core::world::build_and_run(0, nullptr, [this]() {
> +                    qt::core::world::enter_with_task([this]() {
> +                        mBridge = new TelepathyBridge();
> +                    });
> +                });
> +            }).detach();
> +        } catch(const std::system_error& error) {
> +            std::cerr << "exception(std::system_error) in CallMonitor thread start" << error.what() << std::endl;
> +        } catch(...) {
> +            std::cerr << "exception(...) in CallMonitor thread start" << std::endl;
> +        }
> +    }
> +
> +    ~CallMonitorPrivate() {
> +        qt::core::world::destroy();
> +    }
> +
> +    TelepathyBridge *mBridge;
> +};
> +
> +
> +CallMonitor::CallMonitor():
> +    d(new CallMonitorPrivate)
> +{
> +}
> +
> +CallMonitor::~CallMonitor()
> +{
> +    delete d->mBridge;
> +    delete d;
> +}
> +
> +void CallMonitor::on_change(const std::function<void(CallMonitor::State)>& func)
> +{
> +    d->mBridge->on_change(func);
> +}
> +
> +#include "call_monitor.moc"
> +
> 
> === added file 'src/core/media/call-monitor/call_monitor.h'
> --- src/core/media/call-monitor/call_monitor.h	1970-01-01 00:00:00 +0000
> +++ src/core/media/call-monitor/call_monitor.h	2014-11-03 00:57:41 +0000
> @@ -0,0 +1,41 @@
> +/*
> + * Copyright (C) 2014 Canonical Ltd
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License version 3 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + *      Author: Justin McPherson <justin.mcpherson at canonical.com>
> + */
> +
> +
> +#ifndef CALLMONITOR_H
> +#define CALLMONITOR_H
> +
> +#include <functional>
> +
> +class CallMonitorPrivate;
> +
> +class CallMonitor
> +{
> +public:
> +    enum State { OffHook, OnHook };
> +
> +    CallMonitor();
> +    ~CallMonitor();
> +
> +    void on_change(const std::function<void(CallMonitor::State)>& func);
> +
> +private:
> +    CallMonitorPrivate *d;
> +};
> +
> +#endif // CALLMONITOR_H
> 
> === added file 'src/core/media/call-monitor/qtbridge.cpp'
> --- src/core/media/call-monitor/qtbridge.cpp	1970-01-01 00:00:00 +0000
> +++ src/core/media/call-monitor/qtbridge.cpp	2014-11-03 00:57:41 +0000
> @@ -0,0 +1,186 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Jussi Pakkanen <jussi.pakkanen at canonical.com>
> + *              Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#include "qtbridge.h"
> +
> +#include<QCoreApplication>
> +#include<QNetworkAccessManager>
> +#include<QNetworkRequest>
> +#include<QNetworkReply>
> +#include<QThread>
> +#include<QDebug>
> +
> +#include <iostream>
> +
> +namespace
> +{
> +QCoreApplication* app = nullptr;
> +}
> +
> +namespace qt
> +{
> +namespace core
> +{
> +namespace world
> +{
> +namespace detail
> +{
> +QEvent::Type qt_core_world_task_event_type()
> +{
> +    static QEvent::Type event_type = static_cast<QEvent::Type>(QEvent::registerEventType());
> +    return event_type;
> +}
> +
> +class TaskEvent : public QEvent
> +{
> +public:
> +    TaskEvent(const std::function<void()>& task)
> +        : QEvent(qt_core_world_task_event_type()),
> +          task(task)
> +    {
> +    }
> +
> +    void run()
> +    {
> +        try
> +        {
> +            task();
> +            promise.set_value();
> +        } catch(...)
> +        {
> +            promise.set_exception(std::current_exception());
> +        }
> +    }
> +
> +    std::future<void> get_future()
> +    {
> +        return promise.get_future();
> +    }
> +
> +private:
> +    std::function<void()> task;
> +    std::promise<void> promise;
> +};
> +
> +class TaskHandler : public QObject
> +{
> +    Q_OBJECT
> +
> +public:
> +    TaskHandler(QObject* parent) : QObject(parent)
> +    {
> +    }
> +
> +    bool event(QEvent* e);
> +};
> +
> +
> +
> +void createCoreApplicationInstanceWithArgs(int argc, char** argv)
> +{
> +    app = new QCoreApplication(argc, argv);
> +}
> +
> +void destroyCoreApplicationInstace()
> +{
> +    delete app;
> +}
> +
> +QCoreApplication* coreApplicationInstance()
> +{
> +    return app;
> +}
> +
> +TaskHandler* task_handler()
> +{
> +    static TaskHandler* instance = new TaskHandler(coreApplicationInstance());
> +    return instance;
> +}
> +
> +bool TaskHandler::event(QEvent *e)
> +{
> +    if (e->type() != qt_core_world_task_event_type())
> +        return QObject::event(e);
> +
> +    auto te = dynamic_cast<TaskEvent*>(e);
> +    if (te)
> +    {
> +        te->run();
> +        return true;
> +    }
> +
> +    return false;
> +}
> +}
> +
> +void build_and_run(int argc, char** argv, const std::function<void()>& ready)
> +{
> +    QThread::currentThread();
> +    if (QCoreApplication::instance() != nullptr)
> +        throw std::runtime_error(
> +                "qt::core::world::build_and_run: "
> +                "There is already a QCoreApplication running.");
> +
> +    detail::createCoreApplicationInstanceWithArgs(argc, argv);
> +
> +    detail::task_handler()->moveToThread(
> +                detail::coreApplicationInstance()->thread());
> +
> +    // Signal to other worlds that we are good to go.
> +    ready();
> +
> +    detail::coreApplicationInstance()->exec();
> +
> +    // Someone has called quit and we clean up on the correct thread here.
> +    detail::destroyCoreApplicationInstace();
> +}
> +
> +void destroy()
> +{
> +    enter_with_task([]()
> +    {
> +        // We make sure that all tasks have completed before quitting the app.
> +        QEventLoopLocker locker;
> +    }).wait_for(std::chrono::seconds{1});
> +}
> +
> +std::future<void> enter_with_task(const std::function<void()>& task)
> +{
> +    QCoreApplication* instance = QCoreApplication::instance();
> +
> +    if (!instance)
> +    {
> +        throw std::runtime_error("Qt world has not been built before calling this function.");
> +    }
> +
> +    detail::TaskEvent* te = new detail::TaskEvent(task);
> +    auto future = te->get_future();
> +
> +    // We hand over ownership of te here. The event is deleted later after it has
> +    // been processed by the event loop.
> +    instance->postEvent(detail::task_handler(), te);
> +
> +    return future;
> +}
> +
> +}
> +}
> +}
> +
> +#include "qtbridge.moc"
> 
> === added file 'src/core/media/call-monitor/qtbridge.h'
> --- src/core/media/call-monitor/qtbridge.h	1970-01-01 00:00:00 +0000
> +++ src/core/media/call-monitor/qtbridge.h	2014-11-03 00:57:41 +0000
> @@ -0,0 +1,87 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Jussi Pakkanen <jussi.pakkanen at canonical.com>
> + *              Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef QT_CORE_WORLD_BRIDGE_H_
> +#define QT_CORE_WORLD_BRIDGE_H_
> +
> +#include <QObject>
> +
> +#include <functional>
> +#include <future>
> +#include <iostream>
> +
> +namespace qt
> +{
> +namespace core
> +{
> +namespace world
> +{
> +/**
> + * @brief Sets up the Qt core world and executes its event loop. Blocks until destroy() is called.
> + * @param argc Number of arguments in argv.
> + * @param argv Array of command-line arguments.
> + * @param ready Functor be called when the world has been setup and is about to be executed.
> + * @throw std::runtime_error in case of errors.
> + */
> +void build_and_run(int argc, char** argv, const std::function<void()>& ready);
> +
> +/**
> + * @brief Destroys the Qt core world and quits its event loop.
> + */
> +void destroy();
> +
> +/**
> + * @brief Enters the Qt core world and schedules the given task for execution.
> + * @param task The task to be executed in the Qt core world.
> + * @return A std::future that can be waited for to synchronize to the world's internal event loop.
> + */
> +std::future<void> enter_with_task(const std::function<void()>& task);
> +
> +
> +/**
> + * @brief Enters the Qt core world and schedules the given task for execution.
> + * @param task The task to be executed in the Qt core world.
> + * @return A std::future that can be waited for to get hold of the result of the task.
> + */
> +template<typename T>
> +inline std::future<T> enter_with_task_and_expect_result(const std::function<T()>& task)
> +{
> +    std::shared_ptr<std::promise<T>> promise = std::make_shared<std::promise<T>>();
> +    std::future<T> future = promise->get_future();
> +
> +    auto t = [promise, task]()
> +    {
> +        try
> +        {
> +            promise->set_value(task());
> +        } catch(...)
> +        {
> +            promise->set_exception(std::current_exception());
> +        }
> +    };
> +
> +    enter_with_task(t);
> +
> +    return future;
> +}
> +}
> +}
> +}
> +
> +#endif // QT_CORE_WORLD_BRIDGE_H_
> 
> === modified file 'src/core/media/service_implementation.cpp'
> --- src/core/media/service_implementation.cpp	2014-10-15 14:20:03 +0000
> +++ src/core/media/service_implementation.cpp	2014-11-03 00:57:41 +0000
> @@ -20,6 +20,7 @@
>  #include "service_implementation.h"
>  
>  #include "indicator_power_service.h"
> +#include "call-monitor/call_monitor.h"
>  #include "player_configuration.h"
>  #include "player_implementation.h"
>  
> @@ -43,7 +44,8 @@
>      Private()
>          : resume_key(std::numeric_limits<std::uint32_t>::max()),
>            keep_alive(io_service),
> -          disp_cookie(0)
> +          disp_cookie(0),
> +          call_monitor(new CallMonitor)
>      {
>          bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::session));
>          bus->install_executor(dbus::asio::make_executor(bus, io_service));
> @@ -127,6 +129,8 @@
>      int disp_cookie;
>      std::shared_ptr<dbus::Object> uscreen_session;
>      MediaRecorderObserver *observer;
> +    std::unique_ptr<CallMonitor> call_monitor;
> +    std::list<media::Player::PlayerKey> paused_sessions;
>  };
>  
>  media::ServiceImplementation::ServiceImplementation() : d(new Private())
> @@ -148,6 +152,17 @@
>          if (!notifying)
>              resume_multimedia_session();
>      });
> +
> +    d->call_monitor->on_change([this](CallMonitor::State state) {
> +        switch (state) {
> +        case CallMonitor::OffHook:
> +            pause_all_multimedia_sessions();
> +            break;
> +        case CallMonitor::OnHook:
> +            resume_paused_multimedia_sessions();
> +            break;
> +        }
> +    });
>  }
>  
>  media::ServiceImplementation::~ServiceImplementation()
> @@ -216,13 +231,21 @@
>                            if (player->playback_status() == Player::playing
>                                && player->audio_stream_role() == media::Player::multimedia)
>                            {
> -                              d->resume_key = key;
> -                              cout << "Will resume playback of Player with key: " << d->resume_key << endl;
> +                              d->paused_sessions.push_back(key);
>                                player->pause();
>                            }
>                        });
>  }
>  
> +void media::ServiceImplementation::resume_paused_multimedia_sessions()
> +{
> +    std::for_each(d->paused_sessions.begin(), d->paused_sessions.end(), [this](const media::Player::PlayerKey& key) {
> +            player_for_key(key)->play();
> +        });
> +
> +    d->paused_sessions.clear();
> +}
> +
>  void media::ServiceImplementation::resume_multimedia_session()
>  {
>      if (not has_player_for_key(d->resume_key))
> 
> === modified file 'src/core/media/service_implementation.h'
> --- src/core/media/service_implementation.h	2014-09-09 14:48:51 +0000
> +++ src/core/media/service_implementation.h	2014-11-03 00:57:41 +0000
> @@ -42,6 +42,7 @@
>  
>  private:
>      void pause_all_multimedia_sessions();
> +    void resume_paused_multimedia_sessions();
>      void resume_multimedia_session();
>  
>      struct Private;
> 
> === modified file 'tests/unit-tests/CMakeLists.txt'
> --- tests/unit-tests/CMakeLists.txt	2014-10-14 16:21:47 +0000
> +++ tests/unit-tests/CMakeLists.txt	2014-11-03 00:57:41 +0000
> @@ -25,6 +25,7 @@
>  
>      media-hub-common
>      media-hub-client
> +    call-monitor
>      media-hub-test-framework
>  
>      ${CMAKE_THREAD_LIBS_INIT}
> 


-- 
https://code.launchpad.net/~justinmcp/media-hub/1239432/+merge/240387
Your team Ubuntu Phablet Team is subscribed to branch lp:media-hub.



More information about the Ubuntu-reviews mailing list