Clean up custom sound IDs

This commit is contained in:
Max Radermacher 2026-04-29 17:25:18 -05:00 committed by GitHub
parent 4f0c2c3deb
commit 59066a233d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 43 additions and 19 deletions

View File

@ -772,6 +772,7 @@
508C72242C2DFCB2000811F3 /* OWSOutgoingResendResponseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508C72232C2DFCB2000811F3 /* OWSOutgoingResendResponseTest.swift */; };
508F0346296F72F4001D88D0 /* CustomCellBackgroundColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508F0345296F72F4001D88D0 /* CustomCellBackgroundColor.swift */; };
508F05A52FA28308004B96E5 /* CGDataProvider+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508F05A42FA28308004B96E5 /* CGDataProvider+SSK.swift */; };
508F05A72FA294DD004B96E5 /* SoundsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508F05A62FA294DD004B96E5 /* SoundsTest.swift */; };
509085B82C498C3F00409B85 /* HTMLMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9C5CABC289453B200548EEE /* HTMLMetadata.swift */; };
509085BA2C498C4400409B85 /* HTMLMetadataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F94261D4289B1B5400460798 /* HTMLMetadataTests.swift */; };
509085BC2C498D3600409B85 /* LinkPreviewFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509085BB2C498D3500409B85 /* LinkPreviewFetcher.swift */; };
@ -5052,6 +5053,7 @@
508C72232C2DFCB2000811F3 /* OWSOutgoingResendResponseTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSOutgoingResendResponseTest.swift; sourceTree = "<group>"; };
508F0345296F72F4001D88D0 /* CustomCellBackgroundColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomCellBackgroundColor.swift; sourceTree = "<group>"; };
508F05A42FA28308004B96E5 /* CGDataProvider+SSK.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGDataProvider+SSK.swift"; sourceTree = "<group>"; };
508F05A62FA294DD004B96E5 /* SoundsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoundsTest.swift; sourceTree = "<group>"; };
509085BB2C498D3500409B85 /* LinkPreviewFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkPreviewFetcher.swift; sourceTree = "<group>"; };
509085BD2C49C29400409B85 /* PaddingBucket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaddingBucket.swift; sourceTree = "<group>"; };
509085BF2C49C2A500409B85 /* PaddingBucketTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaddingBucketTest.swift; sourceTree = "<group>"; };
@ -14381,6 +14383,7 @@
F94261F0289B1B5400460798 /* RefineryTest.swift */,
F94261EC289B1B5400460798 /* RemoteConfigManagerTests.swift */,
502346782DB03DEB0029DB97 /* SetDequeTest.swift */,
508F05A62FA294DD004B96E5 /* SoundsTest.swift */,
F9613CDD2981F15700894B55 /* SqliteUtilTest.swift */,
C14EC1A82BAA4B5F00A4D064 /* StreamTransformTests.swift */,
7205701F2C8E860300826421 /* StringExtensionTests.swift */,
@ -20324,6 +20327,7 @@
F94262A0289B1B5600460798 /* SMKSecretSessionCipherTest.swift in Sources */,
F9426296289B1B5600460798 /* SMKTestUtils.swift in Sources */,
F9426298289B1B5600460798 /* SMKUDAccessKeyTest.swift in Sources */,
508F05A72FA294DD004B96E5 /* SoundsTest.swift in Sources */,
F9A392B9297F2ED5007964E5 /* SpamReportingTokenRecordTest.swift in Sources */,
F9427EAE297F1EE3008EF0AC /* SpamReportingTokenTest.swift in Sources */,
6664B9AB2A314EBD008EF74B /* SpoilerRevealStateTests.swift in Sources */,

View File

@ -17,10 +17,10 @@ public enum Sound: Equatable {
public extension Sound {
var id: UInt {
var id: UInt64 {
switch self {
case .standard(let standardSound):
return standardSound.rawValue
return UInt64(safeCast: standardSound.rawValue)
case .custom(let customSound):
return customSound.id
}
@ -68,7 +68,8 @@ public extension Sound {
}
}
public enum StandardSound: UInt {
// Limited to 16 bits to avoid colliding with CustomSound.id
public enum StandardSound: UInt16 {
case `default` = 0
// Notification Sounds
@ -207,7 +208,7 @@ public extension StandardSound {
public struct CustomSound {
let id: UInt
let id: UInt64
let filename: String
init(filename: String) {
@ -246,14 +247,12 @@ public struct CustomSound {
// MARK: -
private static let customSoundShift: UInt = 16
// To avoid colliding with StandardSound.rawValue
private static let customSoundShift: Int = 16
private static func idFromFilename(_ filename: String) -> UInt {
let filenameData = Data(filename.utf8)
let hashValue = SHA256.hash(data: filenameData).withUnsafeBytes {
$0.loadUnaligned(as: UInt.self)
}
return hashValue << customSoundShift
static func idFromFilename(_ filename: String) -> UInt64 {
let hashValue = SHA256.hash(data: Data(filename.utf8))
return UInt64(littleEndianData: Data(hashValue))! << customSoundShift
}
}
@ -332,7 +331,7 @@ public class Sounds {
}
public static func systemSoundIDForSound(_ sound: Sound, quiet: Bool) -> SystemSoundID? {
let cacheKey = String(format: "%lu:%d", sound.id, quiet)
let cacheKey = "\(sound.id):\(quiet)"
if let cachedSound = cachedSystemSounds.get(key: cacheKey) {
return cachedSound.id
}
@ -374,8 +373,11 @@ public class Sounds {
public static var defaultNotificationSound: Sound { .standard(.note) }
private static func soundForId(_ soundId: UInt) -> Sound {
if let standardSound = StandardSound(rawValue: soundId) {
private static func soundForId(_ soundId: UInt64) -> Sound {
if
let soundId = UInt16(exactly: soundId),
let standardSound = StandardSound(rawValue: soundId)
{
return .standard(standardSound)
}
if let customSound = CustomSound.all.first(where: { $0.id == soundId }) {
@ -386,7 +388,7 @@ public class Sounds {
public static var globalNotificationSound: Sound {
let soundId = SSKEnvironment.shared.databaseStorageRef.read { transaction in
return keyValueStore.getUInt(soundsStorageGlobalNotificationKey, transaction: transaction)
return keyValueStore.getUInt64(soundsStorageGlobalNotificationKey, transaction: transaction)
}
guard let soundId else { return defaultNotificationSound }
return soundForId(soundId)
@ -432,12 +434,12 @@ public class Sounds {
// user hasn't authenticated after power-cycling their device.
OWSFileSystem.protectFileOrFolder(atPath: defaultSoundUrl.path, fileProtectionType: .none)
keyValueStore.setUInt(sound.id, key: soundsStorageGlobalNotificationKey, transaction: transaction)
keyValueStore.setUInt64(sound.id, key: soundsStorageGlobalNotificationKey, transaction: transaction)
}
public static func notificationSoundWithSneakyTransaction(forThreadUniqueId threadUniqueId: String) -> Sound {
let soundId = SSKEnvironment.shared.databaseStorageRef.read { transaction in
return keyValueStore.getUInt(threadUniqueId, transaction: transaction)
return keyValueStore.getUInt64(threadUniqueId, transaction: transaction)
}
guard let soundId else { return globalNotificationSound }
return soundForId(soundId)
@ -445,7 +447,7 @@ public class Sounds {
public static func setNotificationSound(_ sound: Sound, forThread thread: TSThread) {
SSKEnvironment.shared.databaseStorageRef.write { transaction in
keyValueStore.setUInt(sound.id, key: thread.uniqueId, transaction: transaction)
keyValueStore.setUInt64(sound.id, key: thread.uniqueId, transaction: transaction)
}
}
@ -496,7 +498,7 @@ public class Sounds {
let allInUseSoundIds = SSKEnvironment.shared.databaseStorageRef.read { transaction in
return Set(keyValueStore.allKeys(transaction: transaction).compactMap {
return keyValueStore.getUInt($0, transaction: transaction)
return keyValueStore.getUInt64($0, transaction: transaction)
})
}

View File

@ -0,0 +1,18 @@
//
// Copyright 2026 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import Testing
@testable import SignalServiceKit
struct SoundsTest {
@Test(arguments: [
("Hello.m4a", 7562547131314274304),
("Goodbye.mp4", 10601446312307589120),
])
func testCustomSoundId(testCase: (filename: String, id: UInt64)) {
#expect(CustomSound.idFromFilename(testCase.filename) == testCase.id)
}
}