Merge "android/media_sharing: Add box to enter the v-name to connect to"
diff --git a/go/src/v.io/x/media_sharing/media.vdl b/go/src/v.io/x/media_sharing/media.vdl
index 104b4ea..6ff84b0 100644
--- a/go/src/v.io/x/media_sharing/media.vdl
+++ b/go/src/v.io/x/media_sharing/media.vdl
@@ -9,7 +9,7 @@
// the given URL. The server will rely on the ContentType response
// header it gets when fetching the url to decide how to display
// the media.
- DisplayUrl(url string) error
+ DisplayUrl(url string) error
// DisplayBytes will cause the server to display whatever media is
// sent in the stream. In the case of audio or movie media, the
diff --git a/go/src/v.io/x/media_sharing/mediaclient/mediaclient.go b/go/src/v.io/x/media_sharing/mediaclient/mediaclient.go
index e3dd976..0c90be8 100644
--- a/go/src/v.io/x/media_sharing/mediaclient/mediaclient.go
+++ b/go/src/v.io/x/media_sharing/mediaclient/mediaclient.go
@@ -6,7 +6,12 @@
import (
"fmt"
+ "io"
+ "mime"
+ "net/http"
+ "net/url"
"os"
+ "path/filepath"
"v.io/v23/context"
"v.io/x/lib/cmdline"
@@ -15,7 +20,12 @@
_ "v.io/x/ref/runtime/factories/static"
)
+var stream *bool
+
func main() {
+ stream = root.Flags.Bool("stream", true,
+ "If true stream the data instead of sending the URL.")
+
cmdline.Main(root)
}
@@ -28,12 +38,62 @@
Short: "Share media with a remote display.",
}
+type streamWriter struct {
+ buf []byte
+ stream interface {
+ Send(item []byte) error
+ Close() error
+ }
+}
+
+func (w *streamWriter) Write(p []byte) (n int, err error) {
+ return len(p), w.stream.Send(p)
+}
+
func display(ctx *context.T, env *cmdline.Env, args []string) error {
if len(args) < 2 {
return fmt.Errorf("Both a server and url must be specified.")
}
- name, url := args[0], args[1]
+ name, urlStr := args[0], args[1]
client := media_sharing.MediaSharingClient(name)
- return client.DisplayUrl(ctx, url)
+ if *stream {
+ parsed, err := url.Parse(urlStr)
+ if err != nil {
+ return err
+ }
+
+ var reader io.Reader
+ var mimeType string
+
+ if parsed.Scheme == "file" {
+ file, err := os.Open(parsed.Path)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+ reader = file
+ mimeType = mime.TypeByExtension(filepath.Ext(parsed.Path))
+ } else {
+ resp, err := http.Get(urlStr)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+ reader = resp.Body
+ mimeType = resp.Header.Get("Content-Type")
+ }
+
+ call, err := client.DisplayBytes(ctx, mimeType)
+ if err != nil {
+ return fmt.Errorf("Failed to start RPC: %v", err)
+ }
+ sw := &streamWriter{stream: call.SendStream()}
+ if _, err = io.Copy(sw, reader); err != nil {
+ return fmt.Errorf("Failed copy stream: %v", err)
+ }
+ return call.Finish()
+ } else {
+ return client.DisplayUrl(ctx, urlStr)
+ }
}
diff --git a/go/src/v.io/x/media_sharing/mediaserver/mediaserver.go b/go/src/v.io/x/media_sharing/mediaserver/mediaserver.go
index 5488070..c242fb5 100644
--- a/go/src/v.io/x/media_sharing/mediaserver/mediaserver.go
+++ b/go/src/v.io/x/media_sharing/mediaserver/mediaserver.go
@@ -97,16 +97,19 @@
return nil, err
}
if _, err := io.Copy(tmp, r); err != nil {
+ os.Remove(tmp.Name())
return nil, err
}
+ tmp.Close()
cmd := exec.Command("eog", "--display", ":0", "-f", tmp.Name())
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
stop := func() {
- if cmd.Process != nil {
- if err := cmd.Process.Kill(); err != nil {
- vlog.Errorf("Could not kill eog: %v", err)
- }
+ if err := cmd.Process.Kill(); err != nil {
+ vlog.Errorf("Could not kill eog: %v", err)
}
+ cmd.Wait()
os.Remove(tmp.Name())
}
if err := cmd.Start(); err != nil {
@@ -115,6 +118,47 @@
return stop, nil
}
+type omxHandler struct{}
+
+func (omxHandler) Matches(mimetype string) bool {
+ return strings.HasPrefix(mimetype, "video")
+}
+
+func (omxHandler) Display(ctx *context.T, mimetype string, r io.ReadCloser) (func(), error) {
+ defer r.Close()
+ tmp, err := ioutil.TempFile("", "")
+ if err != nil {
+ return nil, err
+ }
+ if _, err := io.Copy(tmp, r); err != nil {
+ os.Remove(tmp.Name())
+ return nil, err
+ }
+ tmp.Close()
+
+ args := []string{
+ "-b",
+ tmp.Name(),
+ }
+
+ vlog.Infof("Running: omxplayer %s", strings.Join(args, " "))
+
+ cmd := exec.Command("omxplayer", args...)
+ cmd.Stdin = r
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Start(); err != nil {
+ return nil, err
+ }
+ return func() {
+ if err := cmd.Process.Kill(); err != nil {
+ vlog.Errorf("Could not kill omx: %v", err)
+ }
+ cmd.Wait()
+ os.Remove(tmp.Name())
+ }, nil
+}
+
type vlcHandler struct{}
func (vlcHandler) Matches(mimetype string) bool {
@@ -122,11 +166,22 @@
}
func (vlcHandler) Display(ctx *context.T, mimetype string, r io.ReadCloser) (func(), error) {
+ defer r.Close()
+ tmp, err := ioutil.TempFile("", "")
+ if err != nil {
+ return nil, err
+ }
+ if _, err := io.Copy(tmp, r); err != nil {
+ os.Remove(tmp.Name())
+ return nil, err
+ }
+ tmp.Close()
+
args := []string{
"--no-video-title-show",
"--fullscreen",
"--x11-display", ":0",
- "-",
+ tmp.Name(),
"vlc://quit",
}
@@ -134,16 +189,20 @@
args = append([]string{"--audio-visual=visual"}, args...)
}
+ vlog.Infof("Running: vlc %s", strings.Join(args, " "))
+
cmd := exec.Command("vlc", args...)
- cmd.Stdin = r
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
return nil, err
}
return func() {
- r.Close()
if err := cmd.Process.Kill(); err != nil {
vlog.Errorf("Could not kill vlc: %v", err)
}
+ cmd.Wait()
+ os.Remove(tmp.Name())
}, nil
}
@@ -158,6 +217,7 @@
m := &media{
handlers: []handler{
&eogHandler{},
+ &omxHandler{},
&vlcHandler{},
},
}
diff --git a/scripts/update.sh b/scripts/update.sh
index 8ca52c5..4d75470 100755
--- a/scripts/update.sh
+++ b/scripts/update.sh
@@ -11,6 +11,9 @@
cp $V23_ROOT/release/projects/media-sharing/go/bin/linux_arm/* $V23_ROOT/release/go/bin/linux_arm
vbecome --role=identity/role/vprod/publisher device publish --goos=linux --goarch=arm mediaserver
-installation=$(device ls --installation-state=Active vlab/devices/rpi2media/devmgr/apps/mediaserver/* | tail -n 1)
+#installation=$(device ls --installation-state=Active vlab/devices/rpi2media/devmgr/apps/mediaserver/* | tail -n 1)
+installation=$(namespace glob vlab/devices/rpi2media/devmgr/apps/mediaserver/* | tail -n 1)
+instance=$(namespace glob $installation/* | tail -n 1)
-device updateall $installation
+device update -parallelism=BYKIND $installation
+device update -parallelism=BYKIND $instance