2011-11-08 43 views
3

有沒有辦法在瀏覽器中使用JavaScript將圖像,視頻和音頻發送到AirPlay服務器?Javascript:瀏覽器中的Airplay

+0

我真的* *懷疑。 – Blender

+0

[RAOP](http://en.wikipedia.org/wiki/Remote_Audio_Output_Protocol)*已被逆向工程化,但該協議絕對不適用於HTML/JS。也許有一些本地幫助者(例如本地服務器)。 – ephemient

回答

3

在JavaScript中無法做到這一點。但是,您可能可以使用NPAPI插件從瀏覽器運行它(非常痛苦)。

如果你可以運行一個本地服務器,有幾個node.js模塊,這使得這更容易。以下示例將流式發送到附近AirPlay設備的任何音頻文件。

  • 它需要我維護的NPM的airtunes模塊。
  • 它使用FFmpeg轉碼文件。

你可以測試一下:

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

它假定FFmpeg的是位於/ usr/local/bin目錄/ ffmpeg的,而一個AirPlay的設備可用在localhost:5000(你可以試試與Airfoil揚聲器)。

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); 

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);