iPhone und iPod touch Development
Posts 1-3 of 3
-
Christian-Philipp Worring Premium MemberThe company name is only visible to registered members.Audio-Caching im iOS-Safari irgendwie möglich?
Hallo zusammen,
ich sitze nun schon seit einigen Tagen an der Anpassung einer Webanwendung für iOS-Safaris und finde einfach keine Lösung für mein Problem:
Es handelt sich um eine Webanwendung zur Präsentation von Audio-Marketing-Produkten, die ich vor einiger Zeit entwickelt habe. Der Anwender kann sich dort MP3-Beispiele von GEMA-freier Warteschleifen-Musik, Beispiele von professionellen Sprechern etc. anhören.
Die Audio-Wiedergabe funktioniert momentan mit Flash, also muss eine HTML 5- / QuickTime-Alternative für iPhone und iPad her. Grundsätzlich funktionieren meine aktuellen HTML 5 <audio>- und QuickTime-Lösungen auch, haben allerdings beide ein erhebliches Problem, zu dem ich keine Lösung finde:
Anders als bei Flash und in offenbar fast allen HTML 5-fähigen Desktop-Browsern (zumindest unter Windows) landen einmal geladene / abgespielte MP3s im Safari auf meinem iPad 2 nicht im Browser-Cache. Der Safari (bzw. "AppleCoreMedia" - mit diesem Useragent tauchen die Anfragen zumindest in den Apache-Logs auf) erinnert sich nur an ein geladenes MP3 und spielt es ohne neuen Download mehrfach ab, solange nur ein einzelnes <audio>- oder QuickTime-Element im DOM-Tree existiert. Sobald man auf dieses oder andere Element(e) per JavaScript in irgendeiner Form dynamisch Einfluss nimmt (es komplett ersetzt, ein zweites hinzufügt, nur das <source>-Tag ersetzt, nur das src-Attribut eines <source>-Tags ändert, einer QuickTime-Instanz per .SetURL() eine neue Quelle verpasst, eine neue QuickTime-Instanz anlegt etc.), um eine andere MP3-Datei abzuspielen (sei es "sauber" mit .createElement() und .addChild() oder "dreckig" mit .innerHTML), "vergessen" Safari und/oder CoreMedia sofort alle zuvor geladenen Streams.
Sprich: Ich spiele Song A ab - wird geladen und wiedergegeben. Nun kann Song A immer und immer wieder abgespielt werden, ohne dass die Quelle neu heruntergeladen wird. Nun spiele ich Song B ab - wird ebenso geladen und wiedergegeben. Spiele ich nun wieder Song A ab, ist dieser offenbar nicht mehr in irgendeinem Cache vorhanden und wird erneut komplett vom Server geladen. An den zuvor abgespielten Song B erinnert sich der Safari ab diesem Zeitpunkt dann natürlich auch nicht mehr...
Dieses Verhalten ist gelinde gesagt suboptimal - solange das iOS-Gerät in einem WLAN hängt ist das halb so wild, bei UMTS-, EDGE- oder sogar nur GPRS-Verbindungen werden hier allerdings überflüssiger Traffic und unnötige, je nach Bandbreite potentiell enorm lange und nervige Wartezeiten produziert.
Meine bisherigen Lösungsansätze:
Zuerst dachte ich an den Application Cache mit einer Manifest-Datei, auch wenn diese Technik hier ein wenig zweckentfremdet ist, da ich ja kein Set von statischen Dateien habe, die permanent offline zur Verfügung stehen sollen, sondern nur die MP3s, die der Benutzer bereits abgespielt hat.
Theoretisch sollte ein "dynamisches" Manifest möglich sein, das vom Apache PHP-Modul geparst wird und die bereits abgespielten Dateinamen aus der aktuellen PHP-Session holt, z.B.:
<?php
session_start();
header("Content-Type: text/cache-manifest, charset=UTF-8");
echo "CACHE MANIFEST\n";
foreach($_SESSION['playedSongs'] as $song)
{
echo $song."\n";
}
?>
Auf die Session-Variablen könnte man beim Laden/Abspielen einer MP3-Datei per AJAX Einfluss nehmen und das Manifest per window.applicationCache.update() manuell updaten.
Das Ganze hat allerdings zwei Probleme:
Erstens: Es funktioniert nicht. Ich bin nicht mal bis zum Testen eines dynamischen Manifests gekommen...
Mein Testaufbau sieht wie folgt aus:
<!DOCTYPE html>
<html manifest="cache.manifest">
<head>
<title>Test</title>
<script type="text/javascript">
function playStuff(id)
{
if(id == 1)
{
window.document.getElementById("audio").innerHTML = '<audio controls preload="automatic" autobuffer><source src="song01.mp3" type="audio/mp3" /></audio>';
}
else if(id == 2)
{
window.document.getElementById("audio").innerHTML = '<audio controls preload="automatic" autobuffer><source src="song02.mp3" type="audio/mp3" /></audio>';
}
}
</script>
</head>
<body>
<div id="audio"></div><br />
<br />
<input type="button" value="playStuff(1)" onclick="playStuff(1)" />
<input type="button" value="playStuff(2)" onclick="playStuff(2)" />
</body>
</html>
Die cache.manifest:
CACHE MANIFEST
song01.mp3
song02.mp3
Die Manifest-Datei wird vom Apache per AddType-Eintrag in einer .htaccess auch sauber als "text/cache-manifest" zurückgegeben.
Laut Apache-Log funktioniert das soweit auch:
192.168.0.40 - - [23/Jul/2011:12:45:46 +0200] "GET /websql/index2.html HTTP/1.1" 200 2619 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"
192.168.0.40 - - [23/Jul/2011:12:45:46 +0200] "GET /websql/cache.manifest HTTP/1.1" 200 79 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"
192.168.0.40 - - [23/Jul/2011:12:45:46 +0200] "GET /websql/cache.manifest?%3E HTTP/1.1" 200 79 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"
192.168.0.40 - - [23/Jul/2011:12:45:46 +0200] "GET /websql/song02.mp3 HTTP/1.1" 200 120525 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"
192.168.0.40 - - [23/Jul/2011:12:45:46 +0200] "GET /websql/song01.mp3 HTTP/1.1" 200 120525 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"
Bis hierhin habe ich nur die Seite im Safari geladen.
Nach dem Laden und Abspielen von song01.mp3:
192.168.0.40 - - [23/Jul/2011:12:47:25 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 2 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"
192.168.0.40 - - [23/Jul/2011:12:47:25 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"
192.168.0.40 - - [23/Jul/2011:12:47:25 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"
192.168.0.40 - - [23/Jul/2011:12:47:25 +0200] "GET /websql/song01.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"
192.168.0.40 - - [23/Jul/2011:12:47:25 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"
192.168.0.40 - - [23/Jul/2011:12:47:29 +0200] "GET /websql/song01.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"
192.168.0.40 - - [23/Jul/2011:12:47:29 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"
Lade ich jetzt abwechselnd / nacheinander song02.mp3 und wieder song01.mp3, ergibt sich ein identisches Bild: Die MP3s werden jedesmal neu geladen - "AppleCoreMedia" hat also entweder keinen Zugriff auf den Application Cache oder weiß gar nicht von dessen Existenz...
Problem zwei: Sogar wenn das funktionieren würde müsste ich die abzuspielende Datei zunächst in den Application Cache laden - hier scheint es allerdings keine Möglichkeit zu geben, einen "echten" Progress anzuzeigen. Die ProgressEvents, die vom Application Cache abgefeuert werden, geben nur "Datei x von n" an, nicht aber einen "wirklichen" Progress, aus dem man z.B. "100 kB von 520 kB geladen" errechnen könnte, wie es z.B. beim <audio>- und/oder QuickTime-Element und deren ProgressEvents möglich ist.
Mit allen anderen lokalen Speichermöglichkeiten mit denen ich mich befasst habe (Web SQL / Web Database, Local Storage) komme ich leider auch nicht weiter: Ich sehe keine Möglichkeit, die MP3-Daten aus einem fertig geladenen HTML 5 <audio>-Element oder einem QuickTime-Objekt herauszubekommen, so dass ich sie irgendwie irgendwo lokal speichern könnte. Das HTML 5 <canvas>-Element hat eine .toDataURL()-Methode, die offenbar einen Base64-String zurückgibt, den man lokal speichern und später wieder einfügen / benutzen kann - das <audio>-Element hat so etwas offenbar nicht.
Mein letzter - ausgesprochen verzweifelter, "dreckiger" und uneleganter - Versuch: Die MP3s gleich per AJAX und einem "vorgeschalteten" PHP-Skript als Base64-String laden, um sie irgendwie in den Local Storage oder die Web Database des Browsers zu bekommen:
<?php
$infile = 'song01.mp3';
$contents = file_get_contents($infile);
$base64 = base64_encode($contents);
$audio = 'data:audio/mp3;base64,'.$base64;
echo $audio;
?>
Der resultierende AJAX responseText kommt dann ins Source-Attribut eines <source>-Elements innerhalb eines <audio>-Elements. Diese abenteuerliche Lösung funktioniert sogar im Chrome unter Windows - im Safari unter iOS selbstverständlich nicht... Entweder weiß der Safari unter iOS generell nicht mit Base64-URIs umzugehen oder hat eine äußerst geringes Größenlimit für so etwas.
Außerdem bestünde hier auch wieder das Problem der Anzeige eines vernünftigen, aussagekräftigen Progresses, wenn es denn überhaupt funktionieren würde...
Hat evtl. irgendjemand noch eine Idee oder einen Lösungsansatz um bereits abgespielte MP3s im iOS-Safari irgendwie lokal zu cachen, so dass sie nicht jedesmal aufs Neue heruntergeladen werden? Ich bin mit meinem Latein langsam am Ende...
- 24 Jul 2011, 4:41 pm
-
Kay BothfeldThe company name is only visible to registered members.Re: Audio-Caching im iOS-Safari irgendwie möglich?
Hi,
bin zwar nicht im Thema drin, aber ich empfehle bei solchen Dingen eine Anfrage in
http://stackoverflow.com/questions/tagged/iphone. Da treiben sich viele Cracks aus der ganzen Welt herum und gerade auch die spezielleren Nischen, also iphone+HTML5+audi0+... sind oft besetzt (meine sind Accelerometer und Gyroscope :-).
Hoipe that helps
Kay
- 25 Jul 2011, 11:38 am
-
Christian-Philipp Worring Premium MemberThe company name is only visible to registered members.Re^2: Audio-Caching im iOS-Safari irgendwie möglich?
Hallo,
danke, ich habe da jetzt auch nochmal angefragt.
Nach einigen Tagen suchen und testen sieht es mir allerdings stark danach aus, als sei dieses Problem nicht zu lösen...
- 25 Jul 2011, 1:33 pm
