Browse Source
* Add support for ending the inbound stream. Closes #191 * Add a simple success response to API requests * Store inbound broadcast details for admin purposes * Add /api/admin/broadcaster endpoint * Reset broadcaster on disconnect * Move controller to admin directorypull/216/head
7 changed files with 176 additions and 0 deletions
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
package admin |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"net/http" |
||||
|
||||
"github.com/gabek/owncast/controllers" |
||||
"github.com/gabek/owncast/core" |
||||
"github.com/gabek/owncast/models" |
||||
"github.com/gabek/owncast/router/middleware" |
||||
) |
||||
|
||||
// GetInboundBroadasterDetails gets the details of the inbound broadcaster
|
||||
func GetInboundBroadasterDetails(w http.ResponseWriter, r *http.Request) { |
||||
middleware.EnableCors(&w) |
||||
|
||||
broadcaster := core.GetBroadcaster() |
||||
if broadcaster == nil { |
||||
controllers.WriteSimpleResponse(w, false, "no broadcaster connected") |
||||
return |
||||
} |
||||
|
||||
response := inboundBroadasterDetailsResponse{ |
||||
models.BaseAPIResponse{ |
||||
true, |
||||
"", |
||||
}, |
||||
broadcaster, |
||||
} |
||||
|
||||
w.Header().Set("Content-Type", "application/json") |
||||
json.NewEncoder(w).Encode(response) |
||||
} |
||||
|
||||
type inboundBroadasterDetailsResponse struct { |
||||
models.BaseAPIResponse |
||||
Broadcaster *models.Broadcaster `json:"broadcaster"` |
||||
} |
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
package rtmp |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"regexp" |
||||
|
||||
"github.com/gabek/owncast/models" |
||||
"github.com/nareix/joy5/format/flv/flvio" |
||||
) |
||||
|
||||
func getInboundDetailsFromMetadata(metadata []interface{}) (models.RTMPStreamMetadata, error) { |
||||
metadataComponentsString := fmt.Sprintf("%+v", metadata) |
||||
re := regexp.MustCompile(`\{(.*?)\}`) |
||||
submatchall := re.FindAllString(metadataComponentsString, 1) |
||||
|
||||
if len(submatchall) == 0 { |
||||
return models.RTMPStreamMetadata{}, errors.New("unable to parse inbound metadata") |
||||
} |
||||
|
||||
metadataJSONString := submatchall[0] |
||||
var details models.RTMPStreamMetadata |
||||
json.Unmarshal([]byte(metadataJSONString), &details) |
||||
return details, nil |
||||
} |
||||
|
||||
func getAudioCodec(codec interface{}) string { |
||||
var codecID float64 |
||||
if assertedCodecID, ok := codec.(float64); ok { |
||||
codecID = assertedCodecID |
||||
} else { |
||||
return codec.(string) |
||||
} |
||||
|
||||
switch codecID { |
||||
case flvio.SOUND_MP3: |
||||
return "MP3" |
||||
case flvio.SOUND_AAC: |
||||
return "AAC" |
||||
case flvio.SOUND_SPEEX: |
||||
return "Speex" |
||||
} |
||||
|
||||
return "Unknown" |
||||
} |
||||
|
||||
func getVideoCodec(codec interface{}) string { |
||||
var codecID float64 |
||||
if assertedCodecID, ok := codec.(float64); ok { |
||||
codecID = assertedCodecID |
||||
} else { |
||||
return codec.(string) |
||||
} |
||||
|
||||
switch codecID { |
||||
case flvio.VIDEO_H264: |
||||
return "H.264" |
||||
case flvio.VIDEO_H265: |
||||
return "H.265" |
||||
} |
||||
|
||||
return "Unknown" |
||||
} |
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
package models |
||||
|
||||
import "time" |
||||
|
||||
// Broadcaster represents the details around the inbound broadcasting connection.
|
||||
type Broadcaster struct { |
||||
RemoteAddr string `json:"remoteAddr"` |
||||
StreamDetails InboundStreamDetails `json:"streamDetails"` |
||||
Time time.Time `json:"time"` |
||||
} |
||||
|
||||
type InboundStreamDetails struct { |
||||
Width int `json:"width"` |
||||
Height int `json:"height"` |
||||
VideoFramerate int `json:"framerate"` |
||||
VideoBitrate int `json:"videoBitrate"` |
||||
VideoCodec string `json:"videoCodec"` |
||||
AudioBitrate int `json:"audioBitrate"` |
||||
AudioCodec string `json:"audioCodec"` |
||||
Encoder string `json:"encoder"` |
||||
} |
||||
|
||||
// RTMPStreamMetadata is the raw metadata that comes in with a RTMP connection
|
||||
type RTMPStreamMetadata struct { |
||||
Width int `json:"width"` |
||||
Height int `json:"height"` |
||||
VideoBitrate float32 `json:"videodatarate"` |
||||
VideoCodec interface{} `json:"videocodecid"` |
||||
VideoFramerate int `json:"framerate"` |
||||
AudioBitrate float32 `json:"audiodatarate"` |
||||
AudioCodec interface{} `json:"audiocodecid"` |
||||
Encoder string `json:"encoder"` |
||||
} |
Loading…
Reference in new issue