Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Macとオーディオ再生 2024/11/02
Search
Yusuke Ito
November 02, 2024
Programming
1.5k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Macとオーディオ再生 2024/11/02
macOS native Symposium #10 での発表資料です。
https://macos-native.github.io/backnumbers.html
Yusuke Ito
November 02, 2024
More Decks by Yusuke Ito
See All by Yusuke Ito
おうちHackを取り入れた リノベーション事例
yusukeito
0
980
Server Side Swiftを しばらく運用してみた話
yusukeito
0
670
Swift からword2vecを 使ってみる
yusukeito
0
1.2k
Swift Outside the Box
yusukeito
1
2.9k
SwiftでgRPCとProtocolBuffersを使う
yusukeito
4
1.5k
Swift on Raspberry Pi でI2Cデバイスを使う
yusukeito
1
750
Isomorphic Swift
yusukeito
2
700
Swiftの値付きEnumをHackする
yusukeito
0
440
Swift プロトコル指向なCのラッパーを作る
yusukeito
3
1.3k
Other Decks in Programming
See All in Programming
Vibes Containers 〜AIで変わるコンテナ設計と運用〜
tkikuc
2
500
自分的「カンファレンスの楽しみ方」
syumai
0
190
Hono + Inertia + React で LP を構築した話
oukayuka
2
220
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
0
390
DroidKaigi 2026 「個人開発という実験場: Android エンジニアが手にする4つの自由」
slashnephy
0
220
アクセシビリティから考える情報設計
high_g_engineer
0
300
週末にAI-DLCを本気で回したら$1,600溶けた
hbashimizu
0
130
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
2
2.5k
Building an Out-of-Order CPU
latte72
1
720
MIZARU@SPAJAM2026 第二回予選
1901drama
0
110
デプロイ直後のレイテンシスパイクを調べたら、 Railsの仕様にたどり着いた
nhsykym
0
110
「つくるAI」だけではバグは見つからない ~テストに必要な「見つけるAI」を分離させる戦略~
mfunaki
0
230
Featured
See All Featured
4 Signs Your Business is Dying
shpigford
187
23k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.4k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.1k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
580
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
490
Navigating Team Friction
lara
192
16k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
820
Embracing the Ebb and Flow
colly
88
5.2k
Everyday Curiosity
cassininazir
0
310
Automating Front-end Workflow
addyosmani
1369
210k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
Skip the Path - Find Your Career Trail
mkilby
1
220
Transcript
MacͱΦʔσΟΦ࠶ੜ 2024/11/02 Yusuke Ito Symposium #10 macOS
About me • Yusuke Ito • Web (TypeScript, React, Node.js)
macOS ωΠςΟϒΞϓϦ (Minutes) iOS ωΠςΟϒΞϓϦ (App Store Best of 2014) • ϝΠϯWeb͕ͩɺΦʔσΟΦػثͷ։ൃɾ +macOSΞϓϦ https://audio.current.directory/
None
Իσʔλͷجຊ
PCM (LPCM) Linear Pulse Code Modulation Ϗοτਂ=ৼ෯ (16, 24bit) αϯϓϦϯάप(1ඵ͋ͨΓͷׂ)
44.1kHz(CD) 48kHz, 96kHz (Ի੍ָ࡞) Իͷੜσʔλ 0 -32768 32767
LPCMͷσʔλྔ • 44.1kHz (CD) αϯϓϦϯάप • 16bit (CD) Ϗοτਂ •
3 (180ඵ) • 44100 (sample/sec) × 2 (byte, 16bit) × 2 (channel, L R) × 180 (secs) • = 31,752,000 (bytes) ≈ 30 MB (megabytes)
ίϯςφͱίʔσοΫ ίϯςφ: QuickTime (.mov) MPEG-4 (.m4a, .m4v) Ի AAC ө૾
H.264 ϝλσʔλ ΞʔςΟετ໊… ΞϧόϜ໊… ϝλσʔλ ίʔσοΫ: H.264 AAC Apple Lossless MP3, ATRAC (MD) JPEG PNG ϑΝΠϧͷ෦
ίʔσοΫͱσίʔυ Ի AAC σίʔυ LPCM Իੜσʔλ Τϯίʔυ ίʔσοΫ
Mixing & Playback ԻσʔλͷྲྀΕ Χʔωϧ ϛΩαʔ σόΠε 🔊 App A
App B γεςϜܯࠂԻ App C ഉଞϞʔυ OR (αϯϓϦϯάपม) 96kHz 48kHz 44.1kHz 96kHz LPCM LPCM
ΦʔσΟΦAPIΛ͏
Audio APIs on Mac • AVFoundation: ؆୯ʹ͑ΔΫϥε܈ • AVAudioPlayerͳͲ, ϑΝΠϧ(M4A…)ϨϕϧͷΓऔΓ
• Audio Toolbox: • σίʔυɾΤϯίʔυɾαϯϓϦϯάपม(SRC)ͳͲ • Իσʔλ(PCM)ϨϕϧͷΓऔΓ • Core Audio: ϋʔυΣΞͱͷ௨৴ • ϋʔυΣΞΛར༻͢Δ߹ Core Audio Hardware Audio Toolbox AVFoundation
Core Audio Λ͏ ࠷ϨΠϠʔͷAPI • ΦʔσΟΦσόΠεʹग़ྗ͞ΕΔσʔλΛࣗͰίϯτϩʔϧͰ͖Δ • ඞཁͳλΠϛϯάͰίʔϧόοΫ͕ݺΕΔͷͰԻσʔλ(PCMੜσʔλ)Λ ͢ •
σʔλͷ४උ͕࠶ੜʹؒʹ߹͏Α͏ʹ͢Δ • ΠϯλʔϑΣʔεCݴޠ • Audio Toolbox, Core Audio
ԻָPlayerΛ࡞Δ σʔλͷྲྀΕ αϯϓϦϯά पม (SRC) σίʔμʔ ϑΝΠϧ .m4a Apple Lossless
όοϑΝ Core Audio 🔊 औΓʹ͍͘ Audio Toolbox Core Audio LPCM LPCM LPCM Apple Lossless App C ഉଞϞʔυ
ഉଞϞʔυ • API: Hog Mode • ΧʔωϧϛΩαʔΛհ͞ͳ͍ • →αϯϓϦϯάपมͳͲ͕ߦΘΕͳ͍ •
→ଞͷΞϓϦέʔγϣϯͷԻग़ྗ͞Εͳ͍ • ΦʔσΟΦϋʔυΣΞʹΞΫηε • Ի(LPCM)σʔλΛૹͬͯ࠶ੜ
Swift & Concurrency
Swift & Realtime • ϦΞϧλΠϜॲཧͷอূ͞Ε͍ͯͳ͍(ͣ) • Swiftಛ༗ͷॲཧͷΦʔόʔϔου͕͋ΔՄೳੑ • ΫϦςΟΧϧͳͷ࠷ޙͷίʔϧόοΫՕॴͷΈ •
࣮ࡍSwiftͰͳ͠ • ͋ΓͳΒCͰॻ͘ • ͦΕҎ֎ͷՕॴઈରϦΞϧλΠϜͰͳͯ͘ͳ͠
Concurrency • (Իָ࠶ੜPlayerͰ) ฒߦॲཧͷඞཁੑബ͍ • ͨͩ͠… • ಉ͡ΦϒδΣΫτΛڞ༗͢Δ • όοϑΝʔ(ϝϞϦɾϑΝΠϧ),
ΦʔσΟΦσόΠε, σίʔμʔ • ಉ࣌ʹΞΫηε͠ͳ͍Έඞཁ
ಉظॲཧɾഉଞॲཧ • 1ͭͷϦιʔε(ΦϒδΣΫτ)ʹಉ࣌ʹΞΫηε͠ͳ͍Α͏ʹ͢Δ • ಉ࣌ΞΫηεͷྫ • ಡΈࠐΈதʹॻ͖ࠐΉ • εϨουAͰಡΈࠐΈதʹεϨουBͰಡΈࠐΉ
ഉଞॲཧ • ର͕ಉظؔͷ߹ • NIOLock - swift-nio (All Platforms) •
OSAllocatedUnfairLock (macOS 13~)
struct AudioSytemObject { let id: AudioObjectID = ... let lock
= NIOLock() func get(addr: T) throws -> [T.DataType] { try lock.withLock { let memory = ... let statusData = AudioObjectGetPropertyData(id, &propAddr, 0, nil, &propSize, memory) return (0..<count).map { memory[$0] } } } func set(values: [T.DataType], forAddr addr: T) throws { try lock.withLockVoid { ... let status = AudioObjectSetPropertyData(id, &propAddr, 0, nil, UInt32(propSize), memory) } } } कΓ͍ͨΦϒδΣΫτ
όοϑΝ (ϝϞϦ) εϨουB εϨουA ॻ͖ࠐΈ ಡΈࠐΈ
final class PlaybackBuffer { var buffer = Data() let lock
= NIOLock() func write(_ data: Data) { lock.withLockVoid { buffer.append(data) } } func read() -> Data? { return lock.withLock { if buffer.isEmpty { return nil } let buf = buffer buffer.removeAll() // clear data return buf } } }
Actor vs Lock • Actorͩͱisolated context (isolation boundary)Λ͑ΒΕͳ͍ • ݺͼग़͠ݩ͕CͷίʔϧόοΫ(ಉظ)ͷ߹ͳͲ
• nonisolated ʹ͢Δ? →ࣗલͷഉଞॲཧ͕ඞཁ • await ͢Δ? →ಉظઐ༻ίʔϧόοΫͳͷͰෆՄ func AudioIOProc(buffer: PlaybackBuffer, outOutputData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus { let data = buffer.read() memcpy(outOutputData, data, length) ...
ඇಉظؔͷഉଞॲཧ • ϑΝΠϧΛόοϑΝʔͱͯ࣋ͭ͠ • ಡΈࠐΈதॻ͖ࠐ·ͳ͍ (ಡΈࠐΈ͕ऴΘΔ·Ͱͭ) • ॻ͖ࠐΈதಡΈࠐ·ͳ͍ (ॻ͖ࠐΈ͕ऴΘΔ·Ͱͭ) •
ϩοΫ(ͦͷ··)͑ͳ͍ (σουϩοΫ͢Δ) actor FileCache { func write(_ data: Data) async func read() async -> Data? }
όοϑΝ (ϑΝΠϧ) εϨουB εϨουA ॻ͖ࠐΈ ಡΈࠐΈ
actor FileCache { let queue = DispatchQueue(label: "FileCacheQueue", qos: .utility)
let semaphore = DispatchSemaphore(value: 1) func write(_ data: Data) async { await withCheckedContinuation { continuation in queue.async { self.semaphore.wait() Task { await self.write_(data) continuation.resume() self.semaphore.signal() } } } } func read() async -> Data? { await withCheckedContinuation { continuation in queue.async { self.semaphore.wait() Task { let data = await self.read_() continuation.resume(returning: data) self.semaphore.signal() } } } } • ඇಉظؔ Serial Queue & Semaphore(or Mutex) • Actor͚ͩͰಉ࣌ಡΈॻ͖Λ͛ͳ͍߹͕͋Δ • อޢ͍ͨ͠Օॴ͕ඇಉظؔ
εϨουB εϨουA ϑΝΠϧ ҙεϨου ࣌ؒ ॻ͖ࠐΈத Semaphore 1 0 wait()
wait() DispatchQueue signal() Task ҙεϨου 1 ಡΈࠐΈ 0 signal() write() read() 1 Queue Block…
ࢀߟจݙ • Core Audio Overview (Apple) https://developer.apple.com/library/archive/documentation/MusicAudio/Conceptual/ CoreAudioOverview/WhatisCoreAudio/WhatisCoreAudio.html • Xcode
16 & Swift 6 ΩϟονΞοϓ: Swift Concurrencyͷجૅͱ࠷ॏཁϙΠϯτΛ૯෮श (QonceptInc) https://www.youtube.com/watch?v=jJgEtjx8KHY • ʲSwiftʳGrand Central Dispatch (GCD)ͱOperationQueue ·ͱΊ (@shiz) https://qiita.com/shiz/items/693241f41344a9df6d6f • Linuxͷsemaphoreͱmutexͷ࣮ (@watatuki) https://www.docswell.com/s/watatuki/Z7VNJG-2023-08-24-014308
None