Skip to content

Commit

Permalink
Adds mixdown generation
Browse files Browse the repository at this point in the history
  • Loading branch information
crsib committed Jan 17, 2024
1 parent 943ec31 commit 7a8d288
Show file tree
Hide file tree
Showing 13 changed files with 687 additions and 33 deletions.
3 changes: 3 additions & 0 deletions libraries/lib-cloud-audiocom/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ set( SOURCES
sync/LocalProjectSnapshot.h
sync/MissingBlocksUploader.cpp
sync/MissingBlocksUploader.h
sync/MixdownUploader.cpp
sync/MixdownUploader.h
sync/ProjectCloudExtension.cpp
sync/ProjectCloudExtension.h
sync/RemoteProjectSnapshot.cpp
Expand All @@ -54,6 +56,7 @@ set ( LIBRARIES
PRIVATE
lib-sqlite-helpers-interface
lib-crypto-interface
lib-import-export-interface
wavpack::wavpack # Required for the WavPackCompressor
wxwidgets::base # Required to retrieve the OS information
)
Expand Down
21 changes: 19 additions & 2 deletions libraries/lib-cloud-audiocom/CloudSyncService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,23 @@ class DefaultCloudSyncUI : public sync::CloudSyncUI
{
return sync::DownloadConflictResolution::Remote;
}

void OnMixdownStarted() override
{
}

void SetMixdownProgressMessage(const TranslatableString& message) override
{
}

bool OnMixdownProgress(double progress) override
{
return true;
}

void OnMixdownFinished() override
{
}
}; // class DefaultCloudSyncUI

std::mutex& GetResponsesMutex()
Expand Down Expand Up @@ -163,7 +180,7 @@ void PerformProjectGetRequest(
auto removeRequest =
finally([response] { RemovePendingRequest(response); });

const auto& body = response->readAll<std::string>();
auto body = response->readAll<std::string>();

if (response->getError() != NetworkError::NoError)
{
Expand Down Expand Up @@ -698,7 +715,7 @@ void CloudSyncService::CreateSnapshot(AudacityProject& project)
{
auto& cloudExtension = sync::ProjectCloudExtension::Get(project);
mLocalSnapshots.emplace_back(sync::LocalProjectSnapshot::Create(
GetServiceConfig(), GetOAuthService(), cloudExtension,
GetUI(), GetServiceConfig(), GetOAuthService(), cloudExtension,
[this](const auto& update)
{
UpdateProgress();
Expand Down
6 changes: 6 additions & 0 deletions libraries/lib-cloud-audiocom/sync/CloudSyncUI.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <string>

class AudacityProject;
class TranslatableString;

namespace BasicUI
{
Expand Down Expand Up @@ -74,6 +75,11 @@ class CLOUD_AUDIOCOM_API CloudSyncUI /* not final */

virtual DownloadConflictResolution
OnDownloadConflict(const BasicUI::WindowPlacement& placement) = 0;

virtual void OnMixdownStarted() = 0;
virtual void SetMixdownProgressMessage(const TranslatableString& message) = 0;
virtual bool OnMixdownProgress(double progress) = 0;
virtual void OnMixdownFinished() = 0;
}; // class CloudSyncUI

} // namespace cloud::audiocom::sync
95 changes: 87 additions & 8 deletions libraries/lib-cloud-audiocom/sync/DataUploader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,54 @@

#include "DataUploader.h"

#include <variant>

#include <wx/file.h>

#include "CodeConversions.h"

#include "IResponse.h"
#include "Request.h"
#include "NetworkManager.h"

#include "RequestPayload.h"

#include "BasicUI.h"

using namespace audacity::network_manager;

namespace cloud::audiocom::sync
{
using UploadData = std::variant<std::vector<uint8_t>, std::string>;

struct DataUploader::Response final
{
DataUploader& Uploader;
UploadUrls Target;
std::function<void(UploadResult)> Callback;
std::function<bool(double)> ProgressCallback;

int RetriesCount { 3 };
int RetriesLeft { 3 };

std::vector<uint8_t> Data;
std::string MimeType;
UploadData Data;
std::shared_ptr<IResponse> NetworkResponse;

bool UploadFailed { false };

UploadResultCode CurrentResult { UploadResultCode::Success };

Response(
DataUploader& uploader, const UploadUrls& target,
std::vector<uint8_t> data, std::function<void(UploadResult)> callback)
DataUploader& uploader, const UploadUrls& target, UploadData data,
std::string mimeType, std::function<void(UploadResult)> callback,
std::function<bool(double)> progressCallback)
: Uploader { uploader }
, Target { target }
, Callback { std::move(callback) }
, ProgressCallback { std::move(progressCallback) }
, RetriesLeft { RetriesCount }
, MimeType { std::move(mimeType) }
, Data { std::move(data) }
{
PerformUpload();
Expand All @@ -54,10 +69,23 @@ struct DataUploader::Response final
Request request { Target.UploadUrl };
request.setHeader(
common_headers::ContentType,
common_content_types::ApplicationXOctetStream);
MimeType);

NetworkResponse = NetworkManager::GetInstance().doPut (
request, Data.data(), Data.size());
if (std::holds_alternative<std::vector<uint8_t>>(Data))
{
auto data = *std::get_if<std::vector<uint8_t>>(&Data);

NetworkResponse = NetworkManager::GetInstance().doPut(
request, data.data(), data.size());
}
else
{
auto filePath = *std::get_if<std::string>(&Data);

NetworkResponse = NetworkManager::GetInstance().doPut(
request, CreateRequestPayloadStream(filePath));

}

NetworkResponse->setRequestFinishedCallback(
[this](auto)
Expand All @@ -67,6 +95,19 @@ struct DataUploader::Response final
else
OnUploadFailed();
});

NetworkResponse->setUploadProgressCallback(
[this](int64_t current, int64_t total)
{
if (total <= 0)
{
total = 1;
current = 0;
}

if (!ProgressCallback(static_cast<double>(current) / total))
NetworkResponse->abort();
});
}

void OnUploadSucceeded()
Expand Down Expand Up @@ -213,12 +254,50 @@ void DataUploader::CancelAll()

void DataUploader::Upload(
const ServiceConfig&, const UploadUrls& target, std::vector<uint8_t> data,
std::function<void(UploadResult)> callback)
std::function<void(UploadResult)> callback,
std::function<bool(double)> progressCallback)
{
if (!callback)
callback = [](auto...) {};

if (!progressCallback)
progressCallback = [](auto...) { return true; };

auto lock = std::lock_guard { mResponseMutex };

mResponses.emplace_back(std::make_unique<Response>(
*this, target, std::move(data),
audacity::network_manager::common_content_types::ApplicationXOctetStream,
std::move(callback), std::move(progressCallback)));
}

void DataUploader::Upload(
const ServiceConfig& config, const UploadUrls& target, std::string filePath,
std::function<void(UploadResult)> callback,
std::function<bool(double)> progressCallback)
{
if (!callback)
callback = [](auto...) {};

if (!progressCallback)
progressCallback = [](auto...) { return true; };

if (!wxFileExists(audacity::ToWXString(filePath)))
{
if (callback)
callback(UploadResult {
UploadResultCode::UnknownError,
audacity::ToUTF8(XO("File not found").Translation()) });

return;
}

auto lock = std::lock_guard { mResponseMutex };

mResponses.emplace_back(std::make_unique<Response>(
*this, target, std::move(data), std::move(callback)));
*this, target, std::move(filePath),
audacity::network_manager::common_content_types::ApplicationXOctetStream,
std::move(callback), std::move(progressCallback)));
}

void DataUploader::RemoveResponse(Response& response)
Expand Down
8 changes: 7 additions & 1 deletion libraries/lib-cloud-audiocom/sync/DataUploader.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ class DataUploader final

void Upload(
const ServiceConfig& config, const UploadUrls& target,
std::vector<uint8_t> data, std::function<void(UploadResult)> callback);
std::vector<uint8_t> data, std::function<void(UploadResult)> callback,
std::function<bool(double)> progressCallback = {});

void Upload(
const ServiceConfig& config, const UploadUrls& target,
std::string filePath, std::function<void(UploadResult)> callback,
std::function<bool(double)> progressCallback = {});

private:
struct Response;
Expand Down
44 changes: 39 additions & 5 deletions libraries/lib-cloud-audiocom/sync/LocalProjectSnapshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
#include "../ServiceConfig.h"
#include "../OAuthService.h"

#include "BasicUI.h"

#include "BlockHasher.h"
#include "CloudProjectsDatabase.h"
#include "ProjectCloudExtension.h"
#include "DataUploader.h"
#include "MixdownUploader.h"

#include "SampleBlock.h"
#include "Sequence.h"
Expand Down Expand Up @@ -202,10 +205,12 @@ struct LocalProjectSnapshot::ProjectBlocksLock final : private BlockHashCache
};

LocalProjectSnapshot::LocalProjectSnapshot(
Tag, const ServiceConfig& config, const OAuthService& authService,
Tag, CloudSyncUI& ui, const ServiceConfig& config,
const OAuthService& authService,
ProjectCloudExtension& extension, SnapshotOperationUpdated callback)
: mProjectCloudExtension { extension }
, mWeakProject { extension.GetProject() }
, mCloudSyncUI { ui }
, mServiceConfig { config }
, mOAuthService { authService }
, mUpdateCallback { std::move(callback) }
Expand All @@ -218,9 +223,9 @@ LocalProjectSnapshot::~LocalProjectSnapshot()
}

std::shared_ptr<LocalProjectSnapshot> LocalProjectSnapshot::Create(
const ServiceConfig& config, const OAuthService& authService,
ProjectCloudExtension& extension, SnapshotOperationUpdated callback,
bool forceCreateNewProject)
CloudSyncUI& ui, const ServiceConfig& config,
const OAuthService& authService, ProjectCloudExtension& extension,
SnapshotOperationUpdated callback, bool forceCreateNewProject)
{
auto project = extension.GetProject().lock();

Expand All @@ -234,7 +239,7 @@ std::shared_ptr<LocalProjectSnapshot> LocalProjectSnapshot::Create(
}

auto snapshot = std::make_shared<LocalProjectSnapshot>(
Tag {}, config, authService, extension, std::move(callback));
Tag {}, ui, config, authService, extension, std::move(callback));

snapshot->mProjectBlocksLock = std::make_unique<ProjectBlocksLock>(
extension, *project,
Expand Down Expand Up @@ -450,6 +455,31 @@ void LocalProjectSnapshot::OnSnapshotCreated(
});
}
});

BasicUI::CallAfter(
[this, mixdownUrls = response.SyncState.MixdownUrls]
{
auto project = mWeakProject.lock();

if (!project)
return;

if (mProjectCloudExtension.NeedsMixdownSync())
{
mMixdownUploadInProgress.store(true, std::memory_order_release);
mMixdownUploader = MixdownUploader::Upload(
mCloudSyncUI, mServiceConfig, *project, mixdownUrls,
[this](std::string, bool success)
{
if (success)
mProjectCloudExtension.MixdownSynced();

mMixdownUploader.reset();
mMixdownUploadInProgress.store(
false, std::memory_order_release);
});
}
});
}

void LocalProjectSnapshot::MarkSnapshotSynced(int64_t blocksCount)
Expand Down Expand Up @@ -495,6 +525,10 @@ void LocalProjectSnapshot::MarkSnapshotSynced(int64_t blocksCount)
mCompleted.store(true, std::memory_order_release);
mProjectCloudExtension.OnSyncCompleted(true);

// Wait for mixdown upload to complete
while (mMixdownUploadInProgress.load(std::memory_order_acquire))
std::this_thread::sleep_for(std::chrono::milliseconds(100));

mUpdateCallback(
{ this, blocksCount, blocksCount, true, true, true, {} });
});
Expand Down
17 changes: 12 additions & 5 deletions libraries/lib-cloud-audiocom/sync/LocalProjectSnapshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ constexpr auto UNASSIGNED_PROJECT_ID = -1;

class ProjectCloudExtension;
class LocalProjectSnapshot;
class MixdownUploader;
class CloudSyncUI;

struct SnapshotOperationStatus final
{
Expand All @@ -56,14 +58,15 @@ class LocalProjectSnapshot final : public std::enable_shared_from_this<LocalProj

public:
LocalProjectSnapshot(
Tag, const ServiceConfig& config, const OAuthService& authService,
ProjectCloudExtension& extension, SnapshotOperationUpdated callback);
Tag, CloudSyncUI& ui, const ServiceConfig& config,
const OAuthService& authService, ProjectCloudExtension& extension,
SnapshotOperationUpdated callback);
~LocalProjectSnapshot();

static std::shared_ptr<LocalProjectSnapshot> Create(
const ServiceConfig& config, const OAuthService& authService,
ProjectCloudExtension& extension, SnapshotOperationUpdated callback,
bool forceCreateNewProject = false);
CloudSyncUI& ui, const ServiceConfig& config,
const OAuthService& authService, ProjectCloudExtension& extension,
SnapshotOperationUpdated callback, bool forceCreateNewProject = false);

bool IsCompleted() const;

Expand All @@ -84,6 +87,7 @@ class LocalProjectSnapshot final : public std::enable_shared_from_this<LocalProj
ProjectCloudExtension& mProjectCloudExtension;
std::weak_ptr<AudacityProject> mWeakProject;

CloudSyncUI& mCloudSyncUI;
const ServiceConfig& mServiceConfig;
const OAuthService& mOAuthService;

Expand All @@ -94,11 +98,14 @@ class LocalProjectSnapshot final : public std::enable_shared_from_this<LocalProj

std::unique_ptr<MissingBlocksUploader> mMissingBlockUploader;

std::unique_ptr<MixdownUploader> mMixdownUploader;

std::atomic<int64_t> mUploadedBlocks { 0 };
std::atomic<int64_t> mTotalBlocks { 0 };

std::atomic<bool> mProjectUploaded { false };

std::atomic<bool> mCompleted { false };
std::atomic<bool> mMixdownUploadInProgress { false };
};
} // namespace cloud::audiocom::sync
Loading

0 comments on commit 7a8d288

Please sign in to comment.