Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
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
990
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
710
Swiftの値付きEnumをHackする
yusukeito
0
450
Swift プロトコル指向なCのラッパーを作る
yusukeito
3
1.3k
Other Decks in Programming
See All in Programming
Performance Optimization With LLMs
xleitix
0
210
Findy - エンジニア向け会社紹介/Findy Company Deck
findyinc
6
400k
自作Discord音声botをLambda MicroVMsに移行した話 / Migrating My Discord Voice Bot to Lambda MicroVMs
akihisaikeda
0
150
Jetpack Compose Mechanisms
skydoves
3
870
Kotlinize Is Not Just Converting to Kotlin
chigichan24
1
190
複雑なUIコンポーネントとの ⻑い付き合い⽅:波及するバグからテスト戦略を経て、安全な再設計へ
mixplace
0
460
APNsからLive Activityを開始する話
yumnumm
0
180
AIがコードを書いてくれる時代、我々は何を確かめるのか
yosuke_furukawa
PRO
12
4.4k
続・コーディングルールの鮮度を保ちたい / keep-fresh-go-internal-conventions-again
handlename
0
130
AI-Powered Domain-Driven Design
ziobrando
0
320
あなたの await、OS まで届いてる? strace で覗く JavaScript の非同期
hasutosasaki
1
1.5k
AI時代のTerminal環境を UNIX哲学で設計・運用する
yasunori0418
1
220
Featured
See All Featured
Typedesign – Prime Four
hannesfritz
42
3.2k
Crafting Experiences
bethany
1
390
Embracing the Ebb and Flow
colly
88
5.2k
Ten Tips & Tricks for a 🌱 transition
stuffmc
1
270
So, you think you're a good person
axbom
PRO
2
2.2k
Odyssey Design
rkendrick25
PRO
2
890
Un-Boring Meetings
codingconduct
0
460
Speed Design
sergeychernyshev
33
2.2k
The SEO identity crisis: Don't let AI make you average
varn
0
610
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
5
850
Navigating Team Friction
lara
192
16k
Build your cross-platform service in a week with App Engine
jlugia
234
19k
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