Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

iOSDC 2023 Push To Talk

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

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Ͱݟ͍ͨˡ໌೔