shogo4405 / HaishinKit.swift

Camera and Microphone streaming library via RTMP and SRT for iOS, macOS, tvOS and visionOS.
BSD 3-Clause "New" or "Revised" License
2.76k stars 612 forks source link

HLS and TSWriter issue #782

Closed Goule closed 3 years ago

Goule commented 3 years ago

Hello,

Describe the bug I have a sample iOS project with HLS steaming but when the stream is ON I have some issue :

2020-11-18 20:01:44.251023+0100 MultiCam[1150:72246] Metal API Validation Enabled
2020-18-11 20:01:44.333 [Info] [com.haishinkit.HaishinKit] [VideoIOComponent.swift:96] fps > (fps: 30.0, duration: __C.CMTime(value: 100, timescale: 3000, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0))
2020-18-11 20:01:47.546 [Info] [com.haishinkit.HaishinKit] [AudioConverter.swift:94] inSourceFormat > AudioStreamBasicDescription(mSampleRate: 44100.0, mFormatID: 1819304813, mFormatFlags: 12, mBytesPerPacket: 2, mFramesPerPacket: 1, mBytesPerFrame: 2, mChannelsPerFrame: 1, mBitsPerChannel: 16, mReserved: 0)
2020-18-11 20:01:47.548 [Info] [com.haishinkit.HaishinKit] [AudioConverter.swift:81] formatDescription > Optional(<CMAudioFormatDescription 0x280a83700 [0x1de835b40]> {
    mediaType:'soun' 
    mediaSubType:'aac ' 
    mediaSpecific: {
        ASBD: {
            mSampleRate: 44100.000000 
            mFormatID: 'aac ' 
            mFormatFlags: 0x2 
            mBytesPerPacket: 0 
            mFramesPerPacket: 1024 
            mBytesPerFrame: 0 
            mChannelsPerFrame: 1 
            mBitsPerChannel: 0  } 
        cookie: {(null)} 
        ACL: {(null)}
        FormatList Array: {
            Index: 0 
            ChannelLayoutTag: 0x640001 
            ASBD: {
            mSampleRate: 44100.000000 
            mFormatID: 'aac ' 
            mFormatFlags: 0x2 
            mBytesPerPacket: 0 
            mFramesPerPacket: 1024 
            mBytesPerFrame: 0 
            mChannelsPerFrame: 1 
            mBitsPerChannel: 0  }} 
    } 
    extensions: {(null)}
})
2020-18-11 20:01:47.564 [Info] [com.haishinkit.HaishinKit] [AudioConverter.swift:72] actualBitrate > 32000
2020-18-11 20:02:05.736 [Warn] [com.haishinkit.HaishinKit] [TSWriter.swift:347] rotateFileHandle(_:) > Error Domain=NSCocoaErrorDomain Code=4 "“8600.ts” couldn’t be removed." UserInfo={NSUserStringVariant=(
    Remove
), NSFilePath=/private/var/mobile/Containers/Data/Application/A0DCFCF8-EA16-4D82-93B8-4A772C304ECB/tmp/8600.ts, NSUnderlyingError=0x283502ac0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
2020-18-11 20:02:07.761 [Warn] [com.haishinkit.HaishinKit] [TSWriter.swift:347] rotateFileHandle(_:) > Error Domain=NSCocoaErrorDomain Code=4 "“8602.ts” couldn’t be removed." UserInfo={NSUserStringVariant=(
    Remove
), NSFilePath=/private/var/mobile/Containers/Data/Application/A0DCFCF8-EA16-4D82-93B8-4A772C304ECB/tmp/8602.ts, NSUnderlyingError=0x28350d050 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
2020-18-11 20:02:11.792 [Warn] [com.haishinkit.HaishinKit] [TSWriter.swift:347] rotateFileHandle(_:) > Error Domain=NSCocoaErrorDomain Code=4 "“8608.ts” couldn’t be removed." UserInfo={NSUserStringVariant=(
    Remove
), NSFilePath=/private/var/mobile/Containers/Data/Application/A0DCFCF8-EA16-4D82-93B8-4A772C304ECB/tmp/8608.ts, NSUnderlyingError=0x28350b3c0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
2020-18-11 20:02:15.840 [Warn] [com.haishinkit.HaishinKit] [TSWriter.swift:347] rotateFileHandle(_:) > Error Domain=NSCocoaErrorDomain Code=4 "“8612.ts” couldn’t be removed." UserInfo={NSUserStringVariant=(
    Remove
), NSFilePath=/private/var/mobile/Containers/Data/Application/A0DCFCF8-EA16-4D82-93B8-4A772C304ECB/tmp/8612.ts, NSUnderlyingError=0x28350e3a0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

To Reproduce

Here is the iOS code :

import AVFoundation
import HaishinKit
import Photos
import UIKit
import VideoToolbox

class ViewController: UIViewController {

    @IBOutlet private weak var previewView: MTHKView!

    var httpStream = HTTPStream()

    // Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        httpStream.attachAudio(AVCaptureDevice.default(for: AVMediaType.audio)) { error in
            print(error)
        }
        httpStream.attachCamera(DeviceUtil.device(withPosition: .back)) { error in
            print(error)
        }

        previewView.attachStream(httpStream)
    }

    // Methods

    @IBAction func startStream(_ sender: Any) {
        httpStream.publish("hello")

        let httpService = HLSService(domain: "", type: "_http._tcp", name: "HaishinKit", port: 8080)
        httpService.addHTTPStream(httpStream)

        httpService.startRunning()
    }
}
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        let session = AVAudioSession.sharedInstance()
        do {
            // https://stackoverflow.com/questions/51010390/avaudiosession-setcategory-swift-4-2-ios-12-play-sound-on-silent
            if #available(iOS 10.0, *) {
                try session.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetooth])
            } else {
                session.perform(NSSelectorFromString("setCategory:withOptions:error:"), with: AVAudioSession.Category.playAndRecord, with: [
                    AVAudioSession.CategoryOptions.allowBluetooth,
                    AVAudioSession.CategoryOptions.defaultToSpeaker]
                )
                try session.setMode(.default)
            }
            try session.setActive(true)
        } catch {
            print(error)
        }

        return true
    }

Expected behavior See the stream at http://192.168.1.57:8080/hello/playlist.m3u8 (192.168.1.57 is the IP displayed in my iPhone wifi settings on the same wifi my Mac).

Desktop (please complete the following information):

Additional context I can provide you the sample project if needed.

Thanks

shogo4405 commented 3 years ago

Hello, Please try this code.

import AVFoundation
import HaishinKit
import Photos
import UIKit
import VideoToolbox

class ViewController: UIViewController {

    @IBOutlet private weak var previewView: MTHKView!

    var httpStream = HTTPStream()
    // Please use httpService as property.
    var httpService = HTTPService()

    // Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        httpStream.attachAudio(AVCaptureDevice.default(for: AVMediaType.audio)) { error in
            print(error)
        }
        httpStream.attachCamera(DeviceUtil.device(withPosition: .back)) { error in
            print(error)
        }

        previewView.attachStream(httpStream)
    }

    // Methods

    @IBAction func startStream(_ sender: Any) {
        httpService.addHTTPStream(httpStream)
        httpService.startRunning()

        // Please startRunning after publish.
        httpStream.publish("hello")
    }
}
Goule commented 3 years ago

Hello @shogo4405 thanks for your reply.

I'v tested with :

class HLSPublisherViewController: UIViewController {

    @IBOutlet private weak var previewView: MTHKView!

    var httpStream = HTTPStream()

    var httpService = HLSService(domain: "", type: "_http._tcp", name: "HaishinKit", port: 8080)

    // Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        httpStream.attachAudio(AVCaptureDevice.default(for: AVMediaType.audio)) { error in
            print(error)
        }
        httpStream.attachCamera(DeviceUtil.device(withPosition: .back)) { error in
            print(error)
        }

        previewView.attachStream(httpStream)
    }

    // Methods

    @IBAction func startStream(_ sender: Any) {
        httpService.addHTTPStream(httpStream)
        httpService.startRunning()
        httpStream.publish("hello")
    }
}

But I have the same issue.

sokold commented 3 years ago

I got. the same issue here. after I called startStream, I saw these errors in console: (running on iOS 14.2)

[Warn] [com.haishinkit.HaishinKit] [TSWriter.swift:347] rotateFileHandle(_:) > Error Domain=NSCocoaErrorDomain Code=4 "“13041.ts” couldn’t be removed." UserInfo={NSUserStringVariant=( Remove ), NSFilePath=/private/var/mobile/Containers/Data/Application/16A246A4-970E-4F46-A934-55B407D097FF/tmp/13041.ts, NSUnderlyingError=0x2818095f0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

shogo4405 commented 3 years ago

This log is normal. It's not releated that you can't show a stream on your safari. Please show me Safari's JavaScript console log.

[Warn] [com.haishinkit.HaishinKit] [TSWriter.swift:347] rotateFileHandle(_:) > Error Domain=NSCocoaErrorDomain Code=4 "“13041.ts” couldn’t be removed." UserInfo={NSUserStringVariant=( Remove ), NSFilePath=/private/var/mobile/Containers/Data/Application/16A246A4-970E-4F46-A934-55B407D097FF/tmp/13041.ts, NSUnderlyingError=0x2818095f0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

sokold commented 3 years ago

Thanks for the reply. it turned out to be an ip address issue, not related the HaishinKit.swift. I tested by setting up 2 other http servers, they both have the same issue(can't access by ip address like 192.168.1.60), then I found out I can access m3u8 with bonjour name, something like http://iphonename.local:8080/hello/playlist.m3u8. if I ping iphonename.local, it is an address like 169.254.95.189. it seems to be a reserved ip address you get when dhcp doesn't work. but if I set my iphone ip manually, it doesn't help. if I check the ip address when the app launches, it is still 192.168.1.x, not sure why it changes to 168.254 when creating a http server. anyway, it doesn't seem to be related to the lib.