2016-05-31 30 views
1

Hier ist mein Problem: Ich schreibe ein Laravel-Backend, das eine mp3-Datei abliefern muss, die mit dem Android-Standard-Media-Player reproduziert werden muss.

Für das Laravel-Backend muss ich JWT verwenden, um die Authentifizierung zu handhaben, also muss ich bei jeder Anfrage das Feld "Authorization" auf "Bearer {token}" setzen.
Die Laravel Strecke ist „/Lieder/{id}“ und wird auf diese Weise behandelt:Serve mp3 stream für android mit Laravel

public function getSong(Song $song) { 
    $file = new File(storage_path()."/songs/".$song->path.".mp3"); 

    $headers = array(); 
    $headers['Content-Type'] = 'audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3'; 
    $headers['Content-Length'] = $file->getSize(); 
    $headers['Content-Transfer-Encoding'] = 'binary'; 
    $headers['Accept-Range'] = 'bytes'; 
    $headers['Cache-Control'] = 'must-revalidate, post-check=0, pre-check=0'; 
    $headers['Connection'] = 'Keep-Alive'; 
    $headers['Content-Disposition'] = 'attachment; filename="'.$song->path.'.mp3"'; 

    $user = \Auth::user(); 
    if($user->activated_at) { 
     return Response::download($file, $song->path, $headers); 
    } 
    \App::abort(400); 
} 

Auf der Android-Seite ich den Mediaplayer bin mit der MP3-Datei auf diese Weise zu streamen:

media_player = new MediaPlayer(); 
    try { 
     media_player.setAudioStreamType(AudioManager.STREAM_MUSIC); 

     String token = getSharedPreferences("p_shared", MODE_PRIVATE).getString("token", null); 
     Map<String, String> headers = new HashMap<>(); 
     headers.put("Authorization", "Bearer " + token); 

     media_player.setDataSource(
      getApplicationContext(), 
      Uri.parse(ConnectionHelper.SERVER + "/songs/" + song.getId()), 
      headers 
     ); 
    } catch (IOException e) { 
     finish(); 
     Toast.makeText(
       Round.this, 
       "Some error occurred. Retry in some minutes.", 
       Toast.LENGTH_SHORT 
     ).show(); 
    } 
    media_player.setOnCompletionListener(this); 
    media_player.setOnErrorListener(this); 
    media_player.setOnPreparedListener(this); 

Aber jedes Mal, wenn ich den Code ausführen ich eine Portion extra Code -1005 auf den Fehler-Listener, ERROR_CONNECTION_LOST bedeutet.

Antwort

2

Das Problem: Antwort :: Download (...) produziert keinen Strom, so kann ich nicht meine MP3-Datei dienen.

Die Lösung: Wie Symfony HttpFoundation sagt doc. in der versorgenden Datei Absatz:

"if you are serving a static file, you can use a BinaryFileResponse" 

die MP3-Dateien Ich brauche sind Statik in dem Server und in "/storage/Lieder gespeichert dienen/ "so entschied ich mich für die Bedienung .mp3 wurde die BinaryFileResponse und das Verfahren zu verwenden:

use Symfony\Component\HttpFoundation\BinaryFileResponse; 

[...] 

public function getSong(Song $song) { 
    $path = storage_path().DIRECTORY_SEPARATOR."songs".DIRECTORY_SEPARATOR.$song->path.".mp3"); 

    $user = \Auth::user(); 
    if($user->activated_at) { 
     $response = new BinaryFileResponse($path); 
     BinaryFileResponse::trustXSendfileTypeHeader(); 

     return $response; 
    } 
    \App::abort(400); 
} 

Die BinaryFileResponse verarbeitet automatisch die Anfragen und erlaubt Ihnen, die Datei vollständig zu bedienen (indem Sie nur eine Anfrage mit Http 200 Code machen) oder aufgeteilt für langsamere Verbindung (mehr Anfragen mit Http 206 Code und eine letzte Anfrage mit 200 Code).
Wenn Sie die mod_xsendfile haben Sie (um Streaming schneller) durch Zusatz verwenden können:

BinaryFileResponse::trustXSendfileTypeHeader(); 

Der Android-Code muss nicht geändert werden, um die Datei zu streamen.