diff --git a/CMakeLists.txt b/CMakeLists.txt
index 788d2e4fc2bd7105bff43574076c6166eec7f011..c619bc2748f9c789132934b174efef4448a054d8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -72,9 +72,7 @@ SET(ringclient_CONTROLLERS
 
 SET(ringclient_BACKENDS
    src/backends/AddressBookBackend.mm
-   src/backends/MinimalHistoryBackend.mm
-   src/backends/AddressBookBackend.h
-   src/backends/MinimalHistoryBackend.h)
+   src/backends/AddressBookBackend.h)
 
 SET(ringclient_VIEWS
    src/views/CallView.mm
diff --git a/src/AudioPrefsVC.mm b/src/AudioPrefsVC.mm
index cd18ed062e821b2be25e7640df73342723a10849..124893229ab311bfd18b437d3a323ae9b68a537a 100644
--- a/src/AudioPrefsVC.mm
+++ b/src/AudioPrefsVC.mm
@@ -30,6 +30,7 @@
 #import "AudioPrefsVC.h"
 
 #import <audio/settings.h>
+#import <media/recordingmodel.h>
 #import <QUrl>
 #import <audio/inputdevicemodel.h>
 #import <audio/outputdevicemodel.h>
@@ -65,16 +66,16 @@
     [self.inputDeviceList addItemWithTitle:
             Audio::Settings::instance()->inputDeviceModel()->data(qInputIdx, Qt::DisplayRole).toString().toNSString()];
     [self.alwaysRecordingButton setState:
-            Audio::Settings::instance()->isAlwaysRecording()?NSOnState:NSOffState];
+            Media::RecordingModel::instance()->isAlwaysRecording() ? NSOnState:NSOffState];
 
     [self.muteDTMFButton setState:
             Audio::Settings::instance()->areDTMFMuted()?NSOnState:NSOffState];
 
-    if([[Audio::Settings::instance()->recordPath().toNSURL() absoluteString] isEqualToString:@""]) {
+    if([[Media::RecordingModel::instance()->recordPath().toNSURL() absoluteString] isEqualToString:@""]) {
         NSArray * pathComponentArray = [self pathComponentArray];
         [recordingsPathControl setPathComponentCells:pathComponentArray];
     } else {
-        [recordingsPathControl setURL:Audio::Settings::instance()->recordPath().toNSURL()];
+        [recordingsPathControl setURL:Media::RecordingModel::instance()->recordPath().toNSURL()];
     }
 }
 
@@ -85,13 +86,13 @@
 
 - (IBAction)toggleAlwaysRecording:(NSButton *)sender
 {
-    Audio::Settings::instance()->setAlwaysRecording([sender state] == NSOnState);
+    Media::RecordingModel::instance()->setAlwaysRecording([sender state] == NSOnState);
 }
 
 - (IBAction)pathControlSingleClick:(id)sender {
     // Select that chosen component of the path.
     [self.recordingsPathControl setURL:[[self.recordingsPathControl clickedPathComponentCell] URL]];
-    Audio::Settings::instance()->setRecordPath(QUrl::fromNSURL(self.recordingsPathControl.URL));
+    Media::RecordingModel::instance()->setRecordPath(QUrl::fromNSURL(self.recordingsPathControl.URL));
 }
 
 - (IBAction)chooseOutput:(id)sender {
diff --git a/src/CurrentCallVC.mm b/src/CurrentCallVC.mm
index ba9d59f8b586cfa150b7bdc02ea83ffe77a50e59..aa853cbfea684293ff8fd6a9ef51b1495b35f603 100644
--- a/src/CurrentCallVC.mm
+++ b/src/CurrentCallVC.mm
@@ -464,7 +464,7 @@
 }
 
 - (IBAction)toggleRecording:(id)sender {
-    CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::RECORD;
+    CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::RECORD_AUDIO;
 }
 
 - (IBAction)toggleHold:(id)sender {
diff --git a/src/HistoryVC.mm b/src/HistoryVC.mm
index 4073320b4cda1e2a0d11b2672566766bacce4f94..fbdd78eb57943b3fd001b8dd4d7e28d692098e93 100644
--- a/src/HistoryVC.mm
+++ b/src/HistoryVC.mm
@@ -34,8 +34,8 @@
 #import <callmodel.h>
 #import <call.h>
 #import <contactmethod.h>
+#import <localhistorycollection.h>
 
-#import "backends/MinimalHistoryBackend.h"
 #import "QNSTreeController.h"
 
 #define COLUMNID_DAY			@"DayColumn"	// the single column name in our outline view
@@ -80,7 +80,7 @@
     [historyView setTarget:self];
     [historyView setDoubleAction:@selector(placeHistoryCall:)];
 
-    CategorizedHistoryModel::instance()->addCollection<MinimalHistoryBackend>(LoadOptions::FORCE_ENABLED);
+    CategorizedHistoryModel::instance()->addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
 }
 
 - (void)placeHistoryCall:(id)sender
diff --git a/src/backends/MinimalHistoryBackend.h b/src/backends/MinimalHistoryBackend.h
deleted file mode 100644
index 3e5f8899ba6c8317e19d6cf3836ae93407c8fc11..0000000000000000000000000000000000000000
--- a/src/backends/MinimalHistoryBackend.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/************************************************************************************
- *   Copyright (C) 2014-2015 by Savoir-Faire Linux                                  *
- *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>         *
- *                                                                                  *
- *   This library is free software; you can redistribute it and/or                  *
- *   modify it under the terms of the GNU Lesser General Public                     *
- *   License as published by the Free Software Foundation; either                   *
- *   version 2.1 of the License, or (at your option) any later version.             *
- *                                                                                  *
- *   This library 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 library; if not, write to the Free Software            *
- *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA *
- ***********************************************************************************/
-#ifndef MINIMALHISTORYBACKEND_H
-#define MINIMALHISTORYBACKEND_H
-
-#import <collectioninterface.h>
-
-class Call;
-
-template<typename T> class CollectionMediator;
-
-class LIB_EXPORT MinimalHistoryBackend : public CollectionInterface
-{
-public:
-    explicit MinimalHistoryBackend(CollectionMediator<Call>* mediator);
-    virtual ~MinimalHistoryBackend();
-
-    virtual bool load() override;
-    virtual bool reload() override;
-    virtual bool clear() override;
-    virtual QString    name     () const override;
-    virtual QString    category () const override;
-    virtual QVariant   icon     () const override;
-    virtual bool       isEnabled() const override;
-    virtual QByteArray id       () const override;
-    virtual FlagPack<SupportedFeatures>  supportedFeatures() const override;
-    int daysSince(time_t timestamp);
-
-
-private:
-    CollectionMediator<Call>*  m_pMediator;
-};
-
-#endif
diff --git a/src/backends/MinimalHistoryBackend.mm b/src/backends/MinimalHistoryBackend.mm
deleted file mode 100644
index 915094ca76e2ac30d8fb3ecde46c50c5ea8adb4a..0000000000000000000000000000000000000000
--- a/src/backends/MinimalHistoryBackend.mm
+++ /dev/null
@@ -1,292 +0,0 @@
-/************************************************************************************
- *   Copyright (C) 2014-2015 by Savoir-Faire Linux                                       *
- *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>         *
- *                                                                                  *
- *   This library is free software; you can redistribute it and/or                  *
- *   modify it under the terms of the GNU Lesser General Public                     *
- *   License as published by the Free Software Foundation; either                   *
- *   version 2.1 of the License, or (at your option) any later version.             *
- *                                                                                  *
- *   This library 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 library; if not, write to the Free Software            *
- *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA *
- ***********************************************************************************/
-#import "minimalhistorybackend.h"
-
-#import <Cocoa/Cocoa.h>
-
-//Qt
-#import <QtCore/QFile>
-#import <QtCore/QDir>
-#import <QtCore/qlist.h>
-#import <QtCore/QHash>
-#import <QtWidgets/QApplication>
-#import <QtCore/QStandardPaths>
-#import <collectioneditor.h>
-
-//Ring
-#import <call.h>
-#import <account.h>
-#import <person.h>
-#import <contactmethod.h>
-#import <categorizedhistorymodel.h>
-
-#import "../Constants.h"
-
-class MinimalHistoryEditor : public CollectionEditor<Call>
-{
-public:
-    MinimalHistoryEditor(CollectionMediator<Call>* m, MinimalHistoryBackend* parent);
-    virtual bool save       ( const Call* item ) override;
-    virtual bool remove     ( const Call* item ) override;
-    virtual bool batchRemove(const QList<Call*> contacts) override;
-    virtual bool edit       ( Call*       item ) override;
-    virtual bool addNew     ( const Call* item ) override;
-    virtual bool addExisting( const Call* item ) override;
-
-private:
-    virtual QVector<Call*> items() const override;
-
-    //Helpers
-    void saveCall(QTextStream& stream, const Call* call);
-    bool regenFile(const Call* toIgnore);
-
-    //Attributes
-    QVector<Call*> m_lItems;
-    MinimalHistoryBackend* m_pCollection;
-};
-
-MinimalHistoryEditor::MinimalHistoryEditor(CollectionMediator<Call>* m, MinimalHistoryBackend* parent) :
-CollectionEditor<Call>(m),m_pCollection(parent)
-{
-
-}
-
-MinimalHistoryBackend::MinimalHistoryBackend(CollectionMediator<Call>* mediator) :
-CollectionInterface(new MinimalHistoryEditor(mediator,this)),m_pMediator(mediator)
-{
-
-}
-
-MinimalHistoryBackend::~MinimalHistoryBackend()
-{
-
-}
-
-void MinimalHistoryEditor::saveCall(QTextStream& stream, const Call* call)
-{
-    const QString direction = (call->direction()==Call::Direction::INCOMING)?
-    Call::HistoryStateName::INCOMING : Call::HistoryStateName::OUTGOING;
-
-    const Account* a = call->account();
-    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CALLID          ).arg(call->historyId()                     );
-    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::TIMESTAMP_START ).arg(call->startTimeStamp()         );
-    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::TIMESTAMP_STOP  ).arg(call->stopTimeStamp()          );
-    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::ACCOUNT_ID      ).arg(a?QString(a->id()):""          );
-    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::DISPLAY_NAME    ).arg(call->peerName()               );
-    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::PEER_NUMBER     ).arg(call->peerContactMethod()->uri() );
-    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::DIRECTION       ).arg(direction                      );
-    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::MISSED          ).arg(call->isMissed()               );
-    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::RECORDING_PATH  ).arg(call->recordingPath()          );
-    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CONTACT_USED    ).arg(false                          );//TODO
-    if (call->peerContactMethod()->contact()) {
-        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CONTACT_UID  ).arg(
-                                                                                    QString(call->peerContactMethod()->contact()->uid())
-                                                                                    );
-    }
-    stream << "\n";
-    stream.flush();
-}
-
-bool MinimalHistoryEditor::regenFile(const Call* toIgnore)
-{
-    QDir dir(QString('/'));
-    dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + QString());
-
-    QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') +"history.ini");
-    if ( file.open(QIODevice::WriteOnly | QIODevice::Text) ) {
-        QTextStream stream(&file);
-        for (const Call* c : CategorizedHistoryModel::instance()->getHistoryCalls()) {
-            if (c != toIgnore)
-                saveCall(stream, c);
-        }
-        file.close();
-        return true;
-    }
-    return false;
-}
-
-bool MinimalHistoryEditor::save(const Call* call)
-{
-    if (call->collection()->editor<Call>() != this)
-        return addNew(call);
-
-    return regenFile(nullptr);
-}
-
-bool MinimalHistoryEditor::remove(const Call* item)
-{
-    mediator()->removeItem(item);
-    return regenFile(item);
-}
-
-bool MinimalHistoryEditor::batchRemove(const QList<Call*> calls) {
-    QFile::remove(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + "history.ini");
-    return YES;
-}
-
-bool MinimalHistoryEditor::edit( Call* item)
-{
-    Q_UNUSED(item)
-    return false;
-}
-
-bool MinimalHistoryEditor::addNew(const Call* call)
-{
-    QDir dir(QString('/'));
-    dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + QString());
-
-    if ((call->collection() && call->collection()->editor<Call>() == this)  || call->historyId().isEmpty()) return false;
-    //TODO support \r and \n\r end of line
-    QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/')+"history.ini");
-
-    if ( file.open(QIODevice::Append | QIODevice::Text) ) {
-        QTextStream streamFileOut(&file);
-        saveCall(streamFileOut, call);
-        file.close();
-
-        const_cast<Call*>(call)->setCollection(m_pCollection);
-        addExisting(call);
-        return true;
-    }
-    else
-        qWarning() << "Unable to save history";
-    return false;
-}
-
-bool MinimalHistoryEditor::addExisting(const Call* item)
-{
-    m_lItems << const_cast<Call*>(item);
-    mediator()->addItem(item);
-    return true;
-}
-
-QVector<Call*> MinimalHistoryEditor::items() const
-{
-    return m_lItems;
-}
-
-QString MinimalHistoryBackend::name () const
-{
-    return QObject::tr("Minimal history backend");
-}
-
-QString MinimalHistoryBackend::category () const
-{
-    return QObject::tr("History");
-}
-
-QVariant MinimalHistoryBackend::icon() const
-{
-    return QVariant();
-}
-
-bool MinimalHistoryBackend::isEnabled() const
-{
-    return true;
-}
-
-bool MinimalHistoryBackend::load()
-{
-    // get history limit from our preferences set
-    NSInteger historyLimit = [[NSUserDefaults standardUserDefaults] integerForKey:Preferences::HistoryLimit];
-
-    QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') +"history.ini");
-    if ( file.open(QIODevice::ReadOnly | QIODevice::Text) ) {
-        QMap<QString,QString> hc;
-        while (!file.atEnd()) {
-            QByteArray line = file.readLine().trimmed();
-
-            //The item is complete
-            if ((line.isEmpty() || !line.size()) && hc.size()) {
-                Call* pastCall = Call::buildHistoryCall(hc);
-                if (pastCall->peerName().isEmpty()) {
-                    pastCall->setPeerName(QObject::tr("Unknown"));
-                }
-
-                if(daysSince(pastCall->startTimeStamp()) < historyLimit) {
-                    pastCall->setRecordingPath(hc[ Call::HistoryMapFields::RECORDING_PATH ]);
-                    pastCall->setCollection(this);
-
-                    editor<Call>()->addExisting(pastCall);
-                }
-                hc.clear();
-            }
-            // Add to the current set
-            else {
-                const int idx = line.indexOf("=");
-                if (idx >= 0)
-                    hc[line.left(idx)] = line.right(line.size()-idx-1);
-            }
-        }
-        return true;
-    }
-    else
-        qWarning() << "History doesn't exist or is not readable";
-    return false;
-}
-
-int MinimalHistoryBackend::daysSince(time_t timestamp)
-{
-    NSDate *fromDate;
-    NSDate *toDate;
-
-    NSDate* fromDateTime = [NSDate dateWithTimeIntervalSince1970:timestamp];
-
-    NSCalendar *calendar = [NSCalendar currentCalendar];
-
-    [calendar rangeOfUnit:NSCalendarUnitDay startDate:&fromDate
-                 interval:NULL forDate:fromDateTime];
-    [calendar rangeOfUnit:NSCalendarUnitDay startDate:&toDate
-                 interval:NULL forDate:[NSDate date]];
-
-    NSDateComponents *difference = [calendar components:NSCalendarUnitDay
-                                               fromDate:fromDate toDate:toDate options:0];
-
-    return [difference day];
-}
-
-bool MinimalHistoryBackend::reload()
-{
-    return false;
-}
-
-FlagPack<CollectionInterface::SupportedFeatures> MinimalHistoryBackend::supportedFeatures() const
-{
-    return (FlagPack<SupportedFeatures>) (
-                                                     CollectionInterface::SupportedFeatures::NONE  |
-                                                     CollectionInterface::SupportedFeatures::LOAD  |
-                                                     CollectionInterface::SupportedFeatures::CLEAR |
-                                                     CollectionInterface::SupportedFeatures::REMOVE|
-                                                     CollectionInterface::SupportedFeatures::ADD   );
-}
-
-bool MinimalHistoryBackend::clear()
-{
-    editor<Call>()->batchRemove(items<Call>().toList());
-    QList<Call*> calls = items<Call>().toList();
-    for(int i = 0 ; i < calls.count() ; ++i) {
-        CategorizedHistoryModel::instance()->deleteItem(calls[i]);
-    }
-    return true;
-}
-
-QByteArray MinimalHistoryBackend::id() const
-{
-    return "mhb";
-}