feat(chat): persist VMP voice messages as IM attachments

This commit is contained in:
liu weikai
2026-08-10 14:30:20 +08:00
parent b3ebdcea84
commit 0c6068ecee
23 changed files with 2121 additions and 185 deletions
@@ -20,15 +20,29 @@ class FakeVoiceRuntime final : public ui::chat_voice::IVoiceMessageRuntime
return send_available;
}
ui::chat_voice::StartResult requestRecordAndSend(uint32_t target_id) override
ui::chat_voice::StartResult requestRecordAndSend(
const ui::chat_voice::SendRequest& request) override
{
last_target = target_id;
last_target = request.target_id;
last_protocol = request.presentation_protocol;
last_channel = request.presentation_channel;
++request_count;
return result;
}
std::size_t listReceivedMessages(ui::chat_voice::MessageSummary* out_messages,
std::size_t capacity) const override
bool requestStopRecording() override
{
++stop_request_count;
return stop_result;
}
bool isOutboundActive() const override
{
return outbound_active;
}
std::size_t listMessages(ui::chat_voice::MessageSummary* out_messages,
std::size_t capacity) const override
{
if (!out_messages || capacity == 0U)
{
@@ -38,6 +52,19 @@ class FakeVoiceRuntime final : public ui::chat_voice::IVoiceMessageRuntime
return 1U;
}
bool markConversationRead(uint8_t protocol,
uint8_t channel,
uint32_t peer_id,
bool broadcast) override
{
read_protocol = protocol;
read_channel = channel;
read_peer = peer_id;
read_broadcast = broadcast;
++read_request_count;
return read_result;
}
bool requestPlayback(uint64_t local_id) override
{
played_id = local_id;
@@ -48,9 +75,32 @@ class FakeVoiceRuntime final : public ui::chat_voice::IVoiceMessageRuntime
bool send_available = true;
uint32_t last_target = 0U;
uint32_t request_count = 0U;
mutable ui::chat_voice::MessageSummary summary{0xF00DU, 9U, 0U, 123U, false, true};
uint8_t last_protocol = 0U;
uint8_t last_channel = 0U;
uint8_t read_protocol = 0U;
uint8_t read_channel = 0U;
uint32_t read_peer = 0U;
bool read_broadcast = false;
uint32_t read_request_count = 0U;
bool read_result = true;
mutable ui::chat_voice::MessageSummary summary{
0xF00DU,
9U,
0U,
123U,
2000U,
false,
true,
true,
ui::chat_voice::DeliveryState::Sending,
1U,
0U,
false};
uint64_t played_id = 0U;
bool playback_result = true;
uint32_t stop_request_count = 0U;
bool stop_result = true;
bool outbound_active = false;
ui::chat_voice::StartResult result = ui::chat_voice::StartResult::Queued;
};
@@ -59,7 +109,7 @@ void test_unbound_runtime_is_safe()
ui::chat_voice::setRuntime(nullptr);
assert(!ui::chat_voice::isAvailable());
assert(!ui::chat_voice::canRecordAndSend());
assert(ui::chat_voice::requestRecordAndSend(1U) ==
assert(ui::chat_voice::requestRecordAndSend({1U, 1U, 0U}) ==
ui::chat_voice::StartResult::Unsupported);
}
@@ -70,25 +120,46 @@ void test_runtime_forwards_without_transport_coupling()
assert(ui::chat_voice::isAvailable());
assert(ui::chat_voice::canRecordAndSend());
assert(ui::chat_voice::requestRecordAndSend(0x11223344U) ==
assert(ui::chat_voice::requestRecordAndSend({0x11223344U, 1U, 1U}) ==
ui::chat_voice::StartResult::Queued);
assert(runtime.request_count == 1U);
assert(runtime.last_target == 0x11223344U);
assert(runtime.last_protocol == 1U);
assert(runtime.last_channel == 1U);
assert(ui::chat_voice::requestStopRecording());
assert(runtime.stop_request_count == 1U);
runtime.outbound_active = true;
assert(ui::chat_voice::isOutboundActive());
runtime.available = false;
runtime.send_available = false;
runtime.result = ui::chat_voice::StartResult::PrivateContactUnverified;
assert(!ui::chat_voice::isAvailable());
assert(!ui::chat_voice::canRecordAndSend());
assert(ui::chat_voice::requestRecordAndSend(0x55667788U) ==
assert(ui::chat_voice::requestRecordAndSend({0x55667788U, 4U, 0U}) ==
ui::chat_voice::StartResult::PrivateContactUnverified);
assert(runtime.request_count == 2U);
assert(runtime.last_target == 0x55667788U);
assert(runtime.last_protocol == 4U);
ui::chat_voice::MessageSummary summaries[1] = {};
assert(ui::chat_voice::listReceivedMessages(summaries, 1U) == 1U);
assert(ui::chat_voice::listMessages(summaries, 1U) == 1U);
assert(summaries[0].local_id == runtime.summary.local_id);
assert(summaries[0].source_unverified);
assert(summaries[0].outgoing);
assert(summaries[0].delivery == ui::chat_voice::DeliveryState::Sending);
assert(!summaries[0].read);
assert(ui::chat_voice::markConversationRead(1U, 0U, 9U, false));
assert(runtime.read_request_count == 1U);
assert(runtime.read_protocol == 1U);
assert(runtime.read_channel == 0U);
assert(runtime.read_peer == 9U);
assert(!runtime.read_broadcast);
// The legacy name is intentionally only a source-compatible alias. It
// must expose the exact same mixed-direction timeline rather than
// restoring the old receive-only meaning.
assert(ui::chat_voice::listReceivedMessages(summaries, 1U) == 1U);
assert(summaries[0].outgoing);
assert(ui::chat_voice::requestPlayback(summaries[0].local_id));
assert(runtime.played_id == summaries[0].local_id);