Upgrade to Pro — share decks privately, control downloads, hide ads and more …

iOSDC 2023 Push To Talk

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for coe coe
September 02, 2023

iOSDC 2023 Push To Talk

PushToTalkで作るトランシーバー

iOSDC Japan 2023

2023/09/02 11:00〜
Track C
レギュラートーク(20分)

https://fortee.jp/iosdc-japan-2023/proposal/203df2fe-5650-4b10-8211-7fc689322841

Avatar for coe

coe

September 02, 2023
Tweet

More Decks by coe

Other Decks in Technology

Transcript

  1. 1VTIUP5BML 155 ϓογϡɾτΡɾτʔΫ 1551VTIUP5BML ͸ɺ ૹ৴ϘλϯΛԡ͍ͯ͠Δ࣌ʹԻ੠ૹ৴ঢ়ଶͱͳΔԻ੠ ௨࿩ͷํࣜͰ͋ΔɻϓϨετʔΫ 1SFTT5BML ɺ୯৴ ௨৴ͱ΋ɻ൒ೋॏ௨৴ͷҰछͰ͋Δɻແઢి࿩ɾୈࡾ

    ੈ୅ܞଳి࿩ͷ෇ՃαʔϏεͳͲͷଞɺҰ෦ͷΠϯε λϯτϝοηϯδϟʔͷ௨࿩ํࣜͱͯ͠࢖༻͞Ε͍ͯ Δɻ IUUQTKBXJLJQFEJBPSHXJLJϓογϡɾπʔɾτʔΫ
  2. w /55υίϞ w ϓογϡτʔΫ w BV w )FMMP.FTTFOHFS w 4PGUCBOL

    w 4Ұ੪τʔΫ ೔ຊͰͷαʔϏε ͍ͣΕ΋ऴྃ 1VTIUP5BML 155 IUUQTKBXJLJQFEJBPSHXJLJϓογϡɾπʔɾτʔΫ
  3. w 4JHOJOH$BQBCJMJUJFTͷઃఆ w #BDLHSPVOE.PEFTΛ༗ޮԽ w 1VTIUP5BML w 1VTIUP5BMLΛ༗ޮԽ w 1VTI/PUJ

    fi DBUJPOTΛ༗ޮԽ w *OGPQMJTUͷઃఆ w /4.JDSPQIPOF6TBHF%FTDSJQUJPOΛ༗ޮʹ͢Δ ϓϩδΣΫτͷ४උ ࣮૷ͷྲྀΕ
  4. w 15$IBOOFM.BOBHFSͷ࡞੒ w 15$IBOOFM.BOBHFSΛ௨֤ͯ͠छ155ॲཧΛߦ͏ w EFMFHBUFɺSFTUPSBUJPO%FMFHBUF͸ඞਢ w EFMFHBUFͰɺ֤छ155ؔ࿈ͷΠϕϯτΛݕग़ɺॲཧ w SFTUPSBUJPO%FMFHBUFͰɺΞϓϦ͕Ωϧ͞ΕͨΓ୺຤࠶ىಈ࣌

    ʹ෮ؼͰ͖ΔΑ͏ʹ͢Δ w ϦετΞͷ͜ͱΛߟ͑ΔͱΞϓϦىಈ࣌ʹ࡞੒͢Δͷ͕ྑ͞ ͦ͏ DIBOOFM.BOBHFS EFMFHBUFSFTUPSBUJPO%FMFHBUFDPNQMFUJPO)BOEMFS 15$IBOOFM.BOBHFS
  5. w ΞϓϦͰνϟϯωϧʹೖࣨ͢Δ w $IBOOFM*%Λ66*%Ͱࢦఆ w 15$IBOOFM%FTDSJQUPSͰ$IBOOFM৘ใΛઃఆ w ੒ޭͨ͠৔߹ɺDIBOOFM.BOBHFS @EJE+PJO$IBOOFMSFBTPO ͕EFMFHBUFʹ௨஌͞ΕΔ

    w ࣦഊͨ͠৔߹ɺ DIBOOFM.BOBHFS @GBJMFE5P+PJO$IBOOFMFSSPS ͕EFMFHBUF ʹ௨஌͞ΕΔ SFRVFTU+PJO$IBOOFM DIBOOFM66*%EFTDSJQUPS 15$IBOOFM.BOBHFS
  6. w Ի੠ૹ৴Λ։࢝͢Δͱ͖ʹಈ࡞͢Δ w ࣗ෼ͷΞϓϦ͔Βɺ 15$IBOOFM.BOBHFSSFRVFTU#FHJO5SBOTNJUUJOH DIBOOFM6 6*% Λ࣮ߦͨ࣌͠ w 04ͷ1VTI5BMLγεςϜ6*͔Β௨࿩ϘλϯΛԡͨ࣌͠

    w ϋϯζϑϦʔϘλϯΛԡͨ࣌͠ w Ի੠ૹ৴લͷ४උΛߦ͏ DIBOOFM.BOBHFS @DIBOOFM66*%EJE#FHJO5SBOTNJUUJOH'SPN 15$IBOOFM.BOBHFS%FMFHBUF
  7. w αʔό͸ɺ"QQ͔Βड͚ͨϦΫΤετ৘ใΛݩʹ"1/T΁໨తͷ୺ ຤ʹ155༻ͷ1VTI௨஌ϦΫΤετΛߦ͏ w ΤϯυϙΠϯτ͸௨ৗͷ1VTI௨஌ͱಉ͡ w IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPO VTFSOPUJ fi DBUJPOT

    TFUUJOH@VQ@B@SFNPUF@OPUJ fi DBUJPO@TFSWFS TFOEJOH@OPUJ fi DBUJPO@SFRVFTUT@UP@BQOT w 155༻1VTI௨஌ͷύϥϝʔλ͕ඞཁʹͳΔ w ϖΠϩʔυ͸ඞཁʹԠͯ͡ઃఆ τʔΫͷ։࢝௨஌ αʔόˠ"1/T ࣮૷ͷྲྀΕ
  8. w 1VTI5P5BML༻௨஌Λड͚औͬͨ࣌ʹݺ͹ΕΔ w 151VTI3FTVMUΛଈ࣌ʹฦ͢ඞཁ͕͋Δ w BDUJWF3FNPUF1BSUJDJQBOU w ݱࡏ࿩͍ͯ͠Δ૬ख͕͍Δ w MFBWF$IBOOFM

    w νϟϯωϧ͔Βୀग़͢Δʢ૬ख͕͍ͳ͘ͳͬͨʣ w ΦʔσΟΦηογϣϯ΋༗ޮʹͳΔ EJE"DUJWBUF JODPNJOH1VTI3FTVMU DIBOOFM.BOBHFSDIBOOFM66*%QVTI1BZMPBE 15$IBOOFM.BOBHFS%FMFHBUF
  9. w "QQଆͰνϟϯωϧ͔Βୀग़͢Δ w ࣗ෼ͷΞϓϦ͔Βɺ 15$IBOOFM.BOBHFSMFBWF$IBOOFM DIBOOFM66*% Λ࣮ߦ͠ ͨ࣌ w 04ͷ1VTI5BMLγεςϜ6*͔Β

    w ୀग़Ͱ͖ͨ৔߹ɺ DIBOOFM.BOBHFS @EJE-FBWF$IBOOFMSFBTPO ͕ݺ͹ΕΔ νϟϯωϧ͔Βୀग़ "QQ ࣮૷ͷྲྀΕ
  10. w "QQଆͰDIBOOFM.BOBHFS @EJE-FBWF$IBOOFMSFBTPO Λड͚ ͨࡍʹɺαʔό΁ୀग़ͨ͜͠ͱΛ௨஌ w αʔό͸νϟϯωϧͷঢ়گΛௐ΂Δ w νϟϯωϧʹଞͷϝϯόʔ͕͍ͳ͘ͳͬͨ৔߹ɺϖΠϩʔυʹ ୀग़ͷ৘ใΛؚΊͯ"1/T΁௨஌

    w JODPNJOH1VTI3FTVMUΛड͚ͨ୺຤͸ɺϖΠϩʔυʹୀग़ͷ৘ใ ؚ͕·Ε͍ͯΔ৔߹ɺMFBWF$IBOOFMΛฦ͢Α͏ʹ͢Δ νϟϯωϧ͔Βୀग़ 4FSWFSˠ"1/T ࣮૷ͷྲྀΕ
  11. w ϦΞϧλΠϜͷ࿥Իʹ͸"7$BQUVSF"VEJP%BUB0VUQVUΛ࢖༻ w "7$BQUVSF4FTTJPOͷ༻ҙ w "7$BQUVSF4FTTJPOͷ*OQVUΛઃఆ w "7$BQUVSF4FTTJPOͷ0VUQVUͱͯ͠ "7$BQUVSF"VEJP%BUB0VUQVUΛઃఆ w

    TFU4BNQMF#V ff FS%FMFHBUFͰσϦήʔτΛઃఆ͓ͯ͘͠ w "7$BQUVSF"VEJP%BUB0VUQVU4BNQMF#V ff FS%FMFHBUF͔ΒɺԻ੠ σʔλͱͳΔ$.4BNQMF#V ff FSΛऔಘ Ի੠ͷ࿥Ի 155Ի੠ͷॲཧ
  12. Ի੠ͷ࿥Ի "7$BQUVSF"VEJP%BUB0VUQVU let captureSession = AVCaptureSession() let captureAudioDataOutput = AVCaptureAudioDataOutput()

    guard let audioDevice = AVCaptureDevice.default(for: .audio) else { return } let audioInput = try AVCaptureDeviceInput(device: audioDevice) if captureSession.canAddInput(audioInput) { captureSession.addInput(audioInput) } // DelegateΛࢦఆ captureAudioDataOutput.setSampleBufferDelegate(self, queue: DispatchQueue.global()) if captureSession.canAddOutput(captureAudioDataOutput) { captureSession.addOutput(captureAudioDataOutput) } captureSession.startRunning() ࿥Ի༻ͷηογϣϯΛ࡞੒։࢝
  13. Ի੠ͷ࿥Ի "7$BQUVSF"VEJP%BUB0VUQVU4BNQMF#V ff FS%FMFHBUF // MARK: - AVCaptureAudioDataOutputSampleBufferDelegate func captureOutput(_

    output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { // sampleBuffer͔ΒɺαʔόΞοϓϩʔυʹඞཁͳԻ੠σʔλΛ࡞੒(AVAssetWriterInput) }
  14. "7"TTFU8SJUFSઃఆྫ 155Ի੠ͷॲཧ let audioCompressionSettings: [String: Any] = [ AVFormatIDKey: kAudioFormatMPEG4AAC,

    AVSampleRateKey: 44_100, AVNumberOfChannelsKey: 2, AVEncoderBitRateKey: 160_000 ] assetWriter = AVAssetWriter(contentType: .mpeg4Movie) // not .mpeg4Audio assetWriterInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioCompressionSettings) assetWriter.add(assetWriterInput) assetWriter.outputFileTypeProfile = .mpeg4AppleHLS assetWriter.preferredOutputSegmentInterval = CMTime(seconds: 6, preferredTimescale: 1) assetWriter.initialSegmentStartTime = startTimeOffset assetWriter.delegate = self assetWriter.startWriting() assetWriter.startSession(atSourceTime: startTimeOffset)
  15. "7"TTFU8SJUFS%FMFHBUFͷॲཧ 155Ի੠ͷॲཧ func assetWriter(_ writer: AVAssetWriter, didOutputSegmentData segmentData: Data, segmentType:

    AVAssetSegmentType, segmentReport: AVAssetSegmentReport?) { switch segmentType { case .initialization: // mp4ϑΝΠϧ࡞੒ let fileName = "\(segmentIndex).mp4" try! segmentData.write(to: URL(fileURLWithPath: fileName, isDirectory: false, relativeTo: outputDirectoryURL)) case .separable: // ηάϝϯτϑΝΠϧ࡞੒ let fileName = "\(segmentIndex).m4s" try! segmentData.write(to: URL(fileURLWithPath: fileName, isDirectory: false, relativeTo: outputDirectoryURL)) extinf += "#EXTINF:\(String(format: "%1.5f", segmentReport!.trackReports.first!.duration.seconds)),\t\n\(fileName)\n" @unknown default: print("Skipping segment with unrecognized type") return } // m3u8ϑΝΠϧ࡞੒ generateIndexFile(segmentData, segmentReport: segmentReport) segmentIndex += 1 }
  16. 155Ի੠ͷॲཧ ϓϨΠϦετϑΝΠϧ NV &95.6 &9597&34*0/ &9595"3(&5%63"5*0/ˡQSFGFSSFE0VUQVU4FHNFOU*OUFSWBMͷTFDPOEͱಉҰ &959*/%&1&/%&/54&(.&/54 &959."163*NQ &95*/' 

    ˡ4USJOH GPSNBUG "7"TTFU4FHNFOU3FQPSUUSBDL3FQPSUTGJSTUEVSBUJPOTFDPOET  NT &95*/'   NT &95*/'   NT ʜ
  17. ࣗݾ঺հ ೔޲ڧ w #-&ͰJ04"OESPJEؒͰͦͦ͜͜େ͖ ͳαΠζͷσʔλ௨৴Λ࣮ݱ͢Δ -$"1΋ ͋ΔΑ  w ৄղ4UPSZCPBSE

    w ͋ͳͨͷ஌Βͳ͍࿈བྷઌͷੈք w όοΫάϥ΢ϯυͰΞϓϦ͕Ωϧ͞Ε ͯ΋ා͘ͳ͍ʂΞϓϦͷঢ়ଶΛݩʹ໭͢Ϧε τΞػೳͷશͯ w ྩ࿨࣌୅ͷ9.-ॲཧΛߟ͑Δʙ΋͠ ͋ͳ͕ͨڊେͳ9.-ͱ૬ݟ͑Δ ͍͋·Έ͑ Δ ͜ͱʹͳͬͨΒʙ w खͰ৮ΕͣʹΞϓϦΛಈ͔ٕ͢ज़ w 1VTI5P5BMLͰ࡞Δτϥϯγʔόʔˡ͍ ·͜͜ w ͦΕͰ΋ͳΜͱ͔ͯ͠8FCϖʔδΛ57 ΍8BUDIͰݟ͍ͨˡ໌೔