-
-
Notifications
You must be signed in to change notification settings - Fork 620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add releaseStream support and fix FCPublish call order #1391
Add releaseStream support and fix FCPublish call order #1391
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upon reconsideration of FCPublish/FCUnpublish, it seems more natural for them to exist in RTMPConnection rather than RTMPStream. I believe it would be more appropriate to implement them properly on the RTMPConnection side rather than modifying RTMPStream.
Even if it were to be merged, I have no plans to accept it, as the relevant code itself will be removed in the next version.
Sources/RTMP/RTMPStream.swift
Outdated
@@ -389,6 +389,11 @@ open class RTMPStream: IOStream { | |||
} | |||
} | |||
|
|||
/// Sends a command to the RTMP client or server. | |||
public func send(commandName: String, arguments: Any?...) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[IMO]
RTMPConneciton.call is already public, so I don't feel the need for implementation on the HaishinKit side. We expect it to be defined in the importing side's extension or RTMPStream extension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. connection
is private, but it's injected into the RTMPStream
so it can be used from the outside.
Sources/IO/IOStream.swift
Outdated
@@ -57,6 +57,8 @@ open class IOStream: NSObject { | |||
} | |||
|
|||
/// NetStream has been created. | |||
case uninitialized |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the increase of "uninitialized," the number of states in readyState has increased, making it difficult to foresee and maintain. I also think "closed = uninitialized" is synonymous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering that FCPublish/FCUnpublish will move into RTMPConnection, what could be a way to call releaseStream
before createStream
? I pushed 21a7def with an example so the key can be set from the outside. Initial idea is to subscribe to RTMPConnection.Code.connectSuccess
but there is no guarantee about the event listeners dispatch order, so createStream
might be executed before releaseStream
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you modify createStream as follows, it ensures that the call to createStream will occur after the releaseStream command is received.
func createStream(_ stream: RTMPStream) {
let releaseStreamResponder = RTMPResponder(result: { data -> Void in
let responder = RTMPResponder(result: { data -> Void in
guard let id = data[0] as? Double else {
return
}
stream.id = UInt32(id)
stream.readyState = .open
})
call("createStream", responder: responder)
})
call(“releaseStream”, responder: releaseStreamResponder, arguments: stream.key)
}
In modern times, it cannot be simply assumed whether various server-side implementations are correctly implemented or not. I think it would be good to call it like this.
func createStream(_ stream: RTMPStream) {
// Specify an empty responder to ignore the result of releaseStream.
let releaseStreamResponder = RTMPResponder(result: { data -> Void in })
call(“releaseStream”, responder: releaseStreamResponder, arguments: stream.key)
call(“createStream”, responder: …)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the PR with optional releaseStream call without a responder.
21a7def
to
d59b55b
Compare
In addition to optional Now it's a breaking change because users have to pass |
@@ -282,11 +284,12 @@ public class RTMPConnection: EventDispatcher { | |||
} | |||
|
|||
/// Creates a two-way connection to an application on RTMP Server. | |||
public func connect(_ command: String, arguments: Any?...) { | |||
public func connect(_ command: String, name: String? = nil, arguments: Any?...) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[MUST]
I don't want to make such disruptive changes for the purpose of supporting releaseStream. Also, considering viewing or multiple streams, I still think this change is unnecessary.
If I was to do it, I think it would be better to prepare an RTMPConnection subclass or wrapper class, such as RTMPConnectionFMLECompatible, that conforms to the FMLE sequence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I make RTMPConnection and createStream()
open to allow subclassing? My goal is to have any kind of solution for this case being supported. It's common and solves platform specific issues while not causing others because all other popular encoders perform it in the mentioned sequence. FMLE app performs it in the following order:
AMF command 'releaseStream'
AMF command 'FCPublish'
AMF command 'createStream'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. HaishinKit aims to provide multi-streaming and ingest/playback functionalities. Killing off RTMPConnection functionality or making destructive changes to methods in pursuit of FMLE compatibility would diverge from this objective.
Therefore, I believe it would be appropriate to have a class dedicated to single-stream ingest, inheriting from RTMPConnection, and within that class, call the FMLE-compatible methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems natural for the stream name of releaseStream to be in RTMPStream.
To avoid issues with multi-streaming and playback without inheriting RTMPConnection, this implementation seems necessary.
https://github.com/shogo4405/HaishinKit.swift/pull/1393/files
It might be good to handle errors when there is a contradiction between the publish and fcPublishName, but I don't think it's necessary to be that strict.
Close as #1393 |
Description & motivation
This PR allows the library users to be able to call code before
createStream
. For example, to callreleaseStream
which is supported by Wowza. New state is required because.initialized
is the default state and when the connection is successful, changing the ready state here doesn't lead to the delegate notification call. In addition,createStream
is wrapped into a lock queue, so library users have time to perform extra calls on the same queue before the create stream execution. It also adds an additionalsend
method to allowconnection.call
method call from the outside.Type of change
Please delete options that are not relevant.