4

有没有办法在浏览器中使用 JavaScript 将图像、视频和音频发送到 AirPlay 服务器?

4

2 回答 2

3

It is not possible to achieve this in JavaScript. However, you might be able to run it from the browser with an NPAPI plugin (with great pain).

If you can run a local server, there are several node.js modules which make this much easier. The following example will stream any audio file that is posted to a nearby AirPlay device.

  • It requires the airtunes module from NPM, which I maintain.
  • It uses FFmpeg to transcode the file.

You can test it with:

curl -X POST --data-binary @sample.mp3 http://localhost:8080/audio

It assumes that FFmpeg is located in /usr/local/bin/ffmpeg, and that an AirPlay device is available on localhost:5000 (you can try with Airfoil Speakers).

var airtunes = require('airtunes'),
    express = require('express'),
    app = express(),
    device = airtunes.add('localhost'),
    spawn = require('child_process').spawn;

app.post('/audio', function(req, res) {
  // use ffmpeg to reencode data on the fly
  var ffmpeg = spawn('/usr/local/bin/ffmpeg', [
    '-i', 'pipe:0',       // Read from stdin
    '-f', 's16le',        // PCM 16bits, little-endian
    '-ar', '44100',       // Sampling rate
    '-ac', 2,             // Stereo
    'pipe:1'              // Output to stdout
  ]);

  // pipe data to AirTunes
  ffmpeg.stdout.pipe(airtunes, { end: false });

  // detect if ffmpeg was not spawned correctly
  ffmpeg.stderr.setEncoding('utf8');
  ffmpeg.stderr.on('data', function(data) {
    if(/^execvp\(\)/.test(data)) {
      console.log('failed to start ' + argv.ffmpeg);
      process.exit(1);
    }
  });

  req.pipe(ffmpeg.stdin);

  req.on('end', function() {
    res.end();
 });
});

device.on('status', function(status) {
  console.log('status: ' + status);
});

console.log('listening on port 8080');
app.listen(8080);

于 2012-08-03T10:09:41.253 回答
1

这对我有用

    var xhr = new XMLHttpRequest(),
        xhr_stop = new XMLHttpRequest(),
        hostname = "apple-tv.local",
        port =":7000",
        position = "0";


    xhr_stop.open("POST", "http://" + hostname + port + "/stop", true, "AirPlay", null);
    xhr_stop.send(null);

    xhr.open("POST", "http://" + hostname + port + "/play", true, "AirPlay", null);
    xhr.setRequestHeader("Content-Type", "text/parameters");
    xhr.send("Content-Location: " + url + "\nStart-Position: " + position + "\n");

    // set timer to prevent playback from aborting
    xhr.addEventListener("load", function() { 

        var timer = setInterval(function() {

            var xhr = new XMLHttpRequest(),
                // 0 something wrong; 2 ready to play; >2 playing
                playback_info_keys_count = 0,
                terminate_loop, playback_started;

            xhr.open("GET", "http://" + hostname + port + "/playback-info", true, "AirPlay", null);

            xhr.addEventListener("load", function() {

                playback_info_keys_count = xhr.responseXML.getElementsByTagName("key").length;
                console.log("playback: " + playback_started + "; keys: " + playback_info_keys_count)

                // if we're getting some actual playback info
                if (!playback_started && playback_info_keys_count > 2) {
                    playback_started = true;
                    console.log("setting playback_started = true")
                    terminate_loop = false;
                }

                // playback terminated 
                if (terminate_loop && playback_info_keys_count <= 2) {
                    console.log("stopping loop & setting playback_started = false")
                    clearInterval(timer);
                    var xhr_stop = new XMLHttpRequest();
                    xhr_stop.open("POST", "http://" + hostname + port + "/stop", true, "AirPlay", null);
                    xhr_stop.send(null);                    
                    playback_started = false;
                }

                // playback stopped, AppleTV is "readyToPlay"
                if (playback_started && playback_info_keys_count == 2) {
                    console.log("sending /stop signal, setting playback_started = false")
                    var xhr_stop = new XMLHttpRequest();
                    xhr_stop.open("POST", "http://" + hostname + port + "/stop", true, "AirPlay", null);
                    xhr_stop.send(null);
                    playback_started = false;
                    terminate_loop = true;
                }

            }, false);

            xhr.addEventListener("error", function() {
                clearInterval(timer);
            }, false);
            xhr.send(null);

        }, 5000);

    }, false);
于 2014-11-02T11:34:02.190 回答