@@ -1073,3 +1073,124 @@ func (a *Application) sendAndWaitMediaRecv(payload cast.Payload) (*pb.CastMessag
10731073 }
10741074 return a .sendAndWait (payload , defaultSender , a .application .TransportId , namespaceMedia )
10751075}
1076+
1077+ func (a * Application ) startTranscodingServer (command string ) error {
1078+ if a .httpServer != nil {
1079+ return nil
1080+ }
1081+ a .log ("trying to find available port to start transcoding server on" )
1082+
1083+ listener , err := net .Listen ("tcp" , ":0" )
1084+ if err != nil {
1085+ return errors .Wrap (err , "unable to bind to local tcp address" )
1086+ }
1087+
1088+ a .serverPort = listener .Addr ().(* net.TCPAddr ).Port
1089+ a .log ("found available port :%d" , a .serverPort )
1090+
1091+ a .httpServer = & http.Server {}
1092+
1093+ http .HandleFunc ("/" , func (w http.ResponseWriter , r * http.Request ) {
1094+ // Check to see if we have a 'filename' and if it is one of the ones that have
1095+ // already been validated and is useable.
1096+ filename := r .URL .Query ().Get ("media_file" )
1097+ canServe := false
1098+ for _ , fn := range a .mediaFilenames {
1099+ if fn == filename {
1100+ canServe = true
1101+ }
1102+ }
1103+
1104+ a .playedItems [filename ] = PlayedItem {ContentID : filename , Started : time .Now ().Unix ()}
1105+ a .writePlayedItems ()
1106+
1107+ a .log ("canServe=%t, liveStreaming=%t, filename=%s" , canServe , true , filename )
1108+ if canServe {
1109+ args := strings .Split (command , " " )
1110+ cmd := exec .Command (args [0 ], args [1 :]... )
1111+
1112+ cmd .Stdout = w
1113+ if a .debug {
1114+ cmd .Stderr = os .Stderr
1115+ }
1116+
1117+ w .Header ().Set ("Access-Control-Allow-Origin" , "*" )
1118+ w .Header ().Set ("Transfer-Encoding" , "chunked" )
1119+
1120+ if err := cmd .Run (); err != nil {
1121+ log .WithField ("package" , "application" ).WithFields (logrus.Fields {
1122+ "filename" : filename ,
1123+ }).WithError (err ).Error ("error transcoding" )
1124+ }
1125+ } else {
1126+ http .Error (w , "Invalid file" , 400 )
1127+ }
1128+ a .log ("method=%s, headers=%v, reponse_headers=%v" , r .Method , r .Header , w .Header ())
1129+ pi := a .playedItems [filename ]
1130+
1131+ // TODO(vishen): make this a pointer?
1132+ pi .Finished = time .Now ().Unix ()
1133+ a .playedItems [filename ] = pi
1134+ a .writePlayedItems ()
1135+ })
1136+
1137+ go func () {
1138+ a .log ("media server listening on %d" , a .serverPort )
1139+ if err := a .httpServer .Serve (listener ); err != nil && err != http .ErrServerClosed {
1140+ log .WithField ("package" , "application" ).WithError (err ).Fatal ("error serving HTTP" )
1141+ }
1142+ }()
1143+
1144+ return nil
1145+ }
1146+
1147+ func (a * Application ) Transcode (command string , contentType string ) error {
1148+
1149+ if command == "" || contentType == "" {
1150+ return errors .New ("command and content-type flags needs to be set when transcoding" )
1151+ }
1152+
1153+ filename := "pipe_output"
1154+ // Add the filename to the list of filenames that go-chromecast will serve.
1155+ a .mediaFilenames = append (a .mediaFilenames , filename )
1156+
1157+ localIP , err := a .getLocalIP ()
1158+ if err != nil {
1159+ return err
1160+ }
1161+ a .log ("local IP address: %s" , localIP )
1162+
1163+ a .log ("starting transcoding server..." )
1164+ // Start server to serve the media
1165+ if err := a .startTranscodingServer (command ); err != nil {
1166+ return errors .Wrap (err , "unable to start transcoding server" )
1167+ }
1168+ a .log ("started transcoding server" )
1169+
1170+ // We can only set the content url after the server has started, otherwise we have
1171+ // no way to know the port used.
1172+ contentURL := fmt .Sprintf ("http://%s:%d?media_file=%s" , localIP , a .serverPort , filename )
1173+
1174+ if err := a .ensureIsDefaultMediaReceiver (); err != nil {
1175+ return err
1176+ }
1177+
1178+ // NOTE: This isn't concurrent safe, but it doesn't need to be at the moment!
1179+ a .MediaStart ()
1180+
1181+ // Send the command to the chromecast
1182+ a .sendMediaRecv (& cast.LoadMediaCommand {
1183+ PayloadHeader : cast .LoadHeader ,
1184+ CurrentTime : 0 ,
1185+ Autoplay : true ,
1186+ Media : cast.MediaItem {
1187+ ContentId : contentURL ,
1188+ StreamType : "BUFFERED" ,
1189+ ContentType : contentType ,
1190+ },
1191+ })
1192+
1193+ // Wait until we have been notified that the media has finished playing
1194+ a .MediaWait ()
1195+ return nil
1196+ }
0 commit comments