我如何获得 Android MediaPlayer 运行 我的 http url?与其他 urls 它工作得很好

How I get the Android MediaPlayer running my http url? With other urls it works just fine

所以我想构建一个从我的后端服务器流式传输音乐的应用程序。为此,我用 MongoDB 创建了一个 Node JS Express API。然后我有一个像这样的 url:http://192.168.178.26:3000/stream?id=5dd5065f3b9a2a22149fdb09&format=mp3

当我在我的浏览器 (Opera) 中输入此 url 时,它将按预期播放音乐。也适用于 Postman。

然后我用 Android Studio 为 Android 编写了一个应用程序,它可以从给定的 url 流式传输音乐。当我尝试这个 url: https://www.ssaurel.com/tmp/mymusic.mp3 时效果很好,但我的不行。当我用我的 url 尝试这个时,MediaPlayer 在准备时失败了。错误如下:Prepare failed.: status=0x1。我搜索了这个错误,发现它的意思是 unknown Error.

我的后台代码:

const express = require('express');
const dbHandler = require('./src/dbHandler/dbHandler.js');
const fs = require('fs');
const app = express();

app.get('/stream', (req, res) => {
    console.log(`Got stream request from ${req.ip}...`);
    dbHandler.getFilePath(req.query.id, req.query.format).then((path) => {
        let stat = fs.statSync(path);
        res.set({
            'Content-Type': 'audio/mpeg',
            'Content-Length': stat.size,
            'Accept-Ranges': 'bytes',
            'Cache-Control': 'max-age=3600'
        });
        fs.createReadStream(path).pipe(res);
    }).catch(err => {
        res.status(400).send(err)
    })
})

app.listen(3000, () => {
    console.log(`Server is listening at 3000...`);
    dbHandler.init();
})

如您所见,当服务器收到流请求时,它会将其打印出来。 dbHandler.getFilePath()-方法只是 returns mp3 位置的完整路径,如下所示:D:/Music/song.mp3。当我用邮递员尝试这个时,服务器收到一个请求并打印出来。然后 Postman 取回流,我就可以开始流式传输音乐了。

当我在智能手机上使用浏览器尝试此操作时,它也能正常工作。所以我可以通过智能手机的浏览器播放音乐,但不能使用我的应用程序。

请务必注意,当我尝试准备 MediaPlayer 时,服务器没有收到请求。所以它没有记录到控制台,提交了一个请求。

这是我应用程序的代码:

package sharemusic.truerushhunt3r.de.sharemusic.frontend;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.Toast;

import java.io.IOException;

import sharemusic.truerushhunt3r.de.sharemusic.R;

public class MainActivity extends AppCompatActivity {

    //private GetHandler getHandler;
    private boolean isPlaying = false;
    private boolean initialStage = true;
    private MediaPlayer player;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //getHandler = new GetHandler();
        player = new MediaPlayer();
        player.setAudioStreamType(AudioManager.STREAM_MUSIC);

        ImageButton playButton = findViewById(R.id.playButton);
        playButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!isPlaying) {
                    Log.d("ShareMusic/Button", "Play pressed");
                    Toast.makeText(getApplicationContext(), "Play", Toast.LENGTH_SHORT).show();
                    if (initialStage) {
                        //new Player().execute("https://www.ssaurel.com/tmp/mymusic.mp3");
                        new Player().execute("http://192.168.178.26:3000/stream?id=5dd5065f3b9a2a22149fdb09&format=mp3");                    
                    } else {
                        if (!player.isPlaying()) {
                            player.start();
                        }
                    }
                    isPlaying = true;
                } else {
                    Log.d("ShareMusic/Button", "Pause pressed");
                    Toast.makeText(getApplicationContext(), "Pause", Toast.LENGTH_SHORT).show();
                    if (player.isPlaying()) {
                        player.pause();
                    }

                    isPlaying = false;
                }
            }
        });  
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (player != null) {
            player.reset();
            player.release();
            player = null;
        }
    }

    class Player extends AsyncTask<String, Void, Boolean> {
        @Override
        protected Boolean doInBackground(String... strings) {
            Boolean prepared = false;

            try {
                player.setDataSource(getApplicationContext(), Uri.parse(strings[0]));
                player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        initialStage = true;
                        isPlaying = false;
                        mp.stop();
                        mp.reset();
                    }
                });

                player.prepare();
                prepared = true;
            } catch(Exception e) {
                Log.e("ShareMusic", e.getMessage());
            }
            return prepared;
        }

        @Override
        protected void onPostExecute(Boolean aBoolean) {
            super.onPostExecute(aBoolean);
            if (aBoolean) {
                player.start();
                initialStage = false;
                isPlaying = false;
            } else {
                Toast.makeText(getApplicationContext(), "Failed to prepare", Toast.LENGTH_SHORT).show();
                initialStage = true;
                isPlaying = false;
            }
        }

    }
}

The Response Headers of my url: http://192.168.178.26:3000/stream?id=5dd5065f3b9a2a22149fdb09&format=mp3

The Response Headers of the working url: https://www.ssaurel.com/tmp/mymusic.mp3

我认为这与 http 和 https 协议无关。但我真的不知道现在该怎么办。 android (mp3) 支持我的音乐文件。是我的后端错误还是应用程序?我该如何解决这个问题?

有什么不明白的地方请追问。

Android API 等级:19 及以上

设备:华为P20 Lite

OS: 9.1.0

好的伙计们,我知道了!看看这个 website!基本上你必须写 cleartextTrafficPermitted="true" 而不是 cleartextTrafficPermitted="false" 来让魔法发生。

所以我的结论是,媒体播放器不喜欢 http 连接,但喜欢 https。但是我不明白为什么它不告诉我这个...