Вопрос

У меня была проблема, воспроизводившаяся файл MP3, хранящийся в необработанном ресурсе: когда файл впервые начинает играть, он генерирует, возможно, четверть секунды звука, а затем перезагружается. (Я знаю, что это в основном дубликат описанной проблемы здесь, но предложенное решение не сработало для меня.) Я попробовал несколько вещей и добился некоторого прогресса в проблеме, но оно не полностью исправлено.

Вот как я настраиваюсь, чтобы воспроизвести файл:

mPlayer.reset();
try {
    AssetFileDescriptor afd = getResources().openRawResourceFd(mAudioId);
    if (afd == null) {
        Toast.makeText(mOwner, "Could not load sound.",
                Toast.LENGTH_LONG).show();
        return;
    }
    mPlayer.setDataSource(afd.getFileDescriptor(),
            afd.getStartOffset(), afd.getLength());
    afd.close();
    mPlayer.prepare();
} catch (Exception e) {
    Log.d(LOG_TAG, "Could not load sound.", e);
    Toast.makeText(mOwner, "Could not load sound.", Toast.LENGTH_LONG)
            .show();
}

Если я выйду за деятельность (которая вызывает mPlayer.release()) и вернуться к нему (создавая новый медиаплейер), заикание обычно (но не всегда) исчезает -при условии Я загружаю тот же звуковой файл. Я попробовал пару вещей, которые не имеют значения:

  • Загрузите звуковой файл как актив, а не как ресурс.
  • Создайте медиаплеера, используя MediaPlayer.create(getContext(), mAudioId) и пропустить звонки setDataSource(...) а также prepare().

Затем я заметил, что LogCat всегда показывает эту строку примерно в то время, когда начинается воспроизведение:

DEBUG/AudioSink(37): bufferCount (4) is too small and increased to 12

Это заставило меня задуматься о том, связано ли заикание из -за очевидного отпор. Это привело меня к тому, чтобы попробовать что -то еще:

  • После звонка prepare(), вызов mPlayer.start() и сразу же позвоните mPlayer.pause().

К моему приятному сюрпризу, это имело большой эффект. Большая часть заикания исчезла, плюс нет звука (который я слышу) на самом деле воспроизводится в этот момент процесса.

Тем не менее, это все еще заикается время от времени, когда я звоню mPlayer.start() серьезно. Плюс, это кажется огромным Kludge. Есть ли способ убить эту проблему полностью и чисто?

РЕДАКТИРОВАТЬ Больше информации; не уверен, если связано. Если я позвоню pause() Во время воспроизведения, стремитесь к более ранней должности и позвоните start() Опять же, я слышу короткий бит (~ 1/4 секунды) дополнительного звука, откуда он был приостановлен, прежде чем он начал играть на новой позиции. Это, кажется, указывает на большее количество проблем с буферизацией.

Кроме того, проблемы заикания (и приостановки буфера) появляются на эмуляторах с 1,6 до 3.0.

Это было полезно?

Решение

Afaik The Buffers, которые MediaPlayer создает внутри страны, предназначены для хранения декомпрессированных образцов, а не для хранения предварительных сжатых данных. Я подозреваю, что ваше заикание происходит от медлительности ввода/вывода, поскольку он загружает больше данных MP3 для декомпрессии.

Недавно мне пришлось решить аналогичную проблему с воспроизведением видео. Благодаря MediaPlayer неспособность играть в произвольную InputStream (API странно хромой) Решение, которое я придумал, заключалось в том, чтобы написать небольшой веб-сервер в процессе для обслуживания локальных файлов (на SD-карте) над HTTP. MediaPlayer затем загружает его через URI формы http://127.0.0.1:8888/videofileename.

РЕДАКТИРОВАТЬ:

Ниже приведен класс StreamProxy, который я использую для подачи контента в экземпляр MediaPlayer. Основное использование заключается в том, что вы создаете его создание, запустите его и устанавливаете свой медиаплеер с чем -то вроде MediaPlayer.setDataSource("http://127.0.0.1:8888/localfilepath");

Я должен отметить, что это довольно экспериментально и, вероятно, не совсем без ошибок. Это было написано, чтобы решить аналогичную проблему для вашей, а именно, что MediaPlayer не может воспроизводить файл, который также загружается. Потокая файл локально таким образом работает вокруг этого ограничения (то есть у меня есть поток, загружающий файл, в то время как Streamproxy передает его в MediaPlayer).

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import android.os.AsyncTask;
import android.os.Looper;
import android.util.Log;

public class StreamProxy implements Runnable {

    private static final int SERVER_PORT=8888;

    private Thread thread;
    private boolean isRunning;
    private ServerSocket socket;
    private int port;

    public StreamProxy() {

        // Create listening socket
        try {
          socket = new ServerSocket(SERVER_PORT, 0, InetAddress.getByAddress(new byte[] {127,0,0,1}));
          socket.setSoTimeout(5000);
          port = socket.getLocalPort();
        } catch (UnknownHostException e) { // impossible
        } catch (IOException e) {
          Log.e(TAG, "IOException initializing server", e);
        }

    }

    public void start() {
        thread = new Thread(this);
        thread.start();
    }

    public void stop() {
        isRunning = false;
        thread.interrupt();
        try {
            thread.join(5000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
    }

    @Override
      public void run() {
        Looper.prepare();
        isRunning = true;
        while (isRunning) {
          try {
            Socket client = socket.accept();
            if (client == null) {
              continue;
            }
            Log.d(TAG, "client connected");

            StreamToMediaPlayerTask task = new StreamToMediaPlayerTask(client);
            if (task.processRequest()) {
                task.execute();
            }

          } catch (SocketTimeoutException e) {
            // Do nothing
          } catch (IOException e) {
            Log.e(TAG, "Error connecting to client", e);
          }
        }
        Log.d(TAG, "Proxy interrupted. Shutting down.");
      }




    private class StreamToMediaPlayerTask extends AsyncTask<String, Void, Integer> {

        String localPath;
        Socket client;
        int cbSkip;

        public StreamToMediaPlayerTask(Socket client) {
            this.client = client;
        }

        public boolean processRequest() {
            // Read HTTP headers
            String headers = "";
            try {
              headers = Utils.readTextStreamAvailable(client.getInputStream());
            } catch (IOException e) {
              Log.e(TAG, "Error reading HTTP request header from stream:", e);
              return false;
            }

            // Get the important bits from the headers
            String[] headerLines = headers.split("\n");
            String urlLine = headerLines[0];
            if (!urlLine.startsWith("GET ")) {
                Log.e(TAG, "Only GET is supported");
                return false;               
            }
            urlLine = urlLine.substring(4);
            int charPos = urlLine.indexOf(' ');
            if (charPos != -1) {
                urlLine = urlLine.substring(1, charPos);
            }
            localPath = urlLine;

            // See if there's a "Range:" header
            for (int i=0 ; i<headerLines.length ; i++) {
                String headerLine = headerLines[i];
                if (headerLine.startsWith("Range: bytes=")) {
                    headerLine = headerLine.substring(13);
                    charPos = headerLine.indexOf('-');
                    if (charPos>0) {
                        headerLine = headerLine.substring(0,charPos);
                    }
                    cbSkip = Integer.parseInt(headerLine);
                }
            }
            return true;
        }

        @Override
        protected Integer doInBackground(String... params) {

                        long fileSize = GET CONTENT LENGTH HERE;

            // Create HTTP header
            String headers = "HTTP/1.0 200 OK\r\n";
            headers += "Content-Type: " + MIME TYPE HERE + "\r\n";
            headers += "Content-Length: " + fileSize  + "\r\n";
            headers += "Connection: close\r\n";
            headers += "\r\n";

            // Begin with HTTP header
            int fc = 0;
            long cbToSend = fileSize - cbSkip;
            OutputStream output = null;
            byte[] buff = new byte[64 * 1024];
            try {
                output = new BufferedOutputStream(client.getOutputStream(), 32*1024);                           
                output.write(headers.getBytes());

                // Loop as long as there's stuff to send
                while (isRunning && cbToSend>0 && !client.isClosed()) {

                    // See if there's more to send
                    File file = new File(localPath);
                    fc++;
                    int cbSentThisBatch = 0;
                    if (file.exists()) {
                        FileInputStream input = new FileInputStream(file);
                        input.skip(cbSkip);
                        int cbToSendThisBatch = input.available();
                        while (cbToSendThisBatch > 0) {
                            int cbToRead = Math.min(cbToSendThisBatch, buff.length);
                            int cbRead = input.read(buff, 0, cbToRead);
                            if (cbRead == -1) {
                                break;
                            }
                            cbToSendThisBatch -= cbRead;
                            cbToSend -= cbRead;
                            output.write(buff, 0, cbRead);
                            output.flush();
                            cbSkip += cbRead;
                            cbSentThisBatch += cbRead;
                        }
                        input.close();
                    }

                    // If we did nothing this batch, block for a second
                    if (cbSentThisBatch == 0) {
                        Log.d(TAG, "Blocking until more data appears");
                        Thread.sleep(1000);
                    }
                }
            }
            catch (SocketException socketException) {
                Log.e(TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly");
            }
            catch (Exception e) {
                Log.e(TAG, "Exception thrown from streaming task:");
                Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
                e.printStackTrace();                
            }

            // Cleanup
            try {
                if (output != null) {
                    output.close();
                }
                client.close();
            }
            catch (IOException e) {
                Log.e(TAG, "IOException while cleaning up streaming task:");                
                Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
                e.printStackTrace();                
            }

            return 1;
        }

    }
}

Другие советы

Будет использовать prepareAsync и отвечать на setOnPreparedListener Подходит вам лучше? В зависимости от рабочего процесса вашей деятельности, когда MediaPlayer сначала инициализирован, вы можете установить Подготовка слушателя а затем позвоните mPlayer.prepareAsync() Позже, как только вы на самом деле загружаете ресурс, затем начните воспроизведение там. Я использую что-то подобное, хотя и для сетевого потокового ресурса:

MediaPlayer m_player;
private ProgressDialog m_progressDialog = null;

...

try {
    if (m_player != null) {
    m_player.reset();
    } else {
    m_player = new MediaPlayer();
    }

    m_progressDialog = ProgressDialog
        .show(this,
            getString(R.string.progress_dialog_please_wait),
            getString(R.string.progress_dialog_buffering),
            true);

    m_player.setOnPreparedListener(this);
    m_player.setAudioStreamType(AudioManager.STREAM_MUSIC);
    m_player.setDataSource(someSource);
    m_player.prepareAsync();
} catch (Exception ex) {
}

...

public void onPrepared(MediaPlayer mp) {
    if (m_progressDialog != null && m_progressDialog.isShowing()) {
      m_progressDialog.dismiss();
    }

    m_player.start();
}

Очевидно, что в полном решении есть больше (обработка ошибок и т. Д.), Но я думаю, что это должно работать как хороший пример, который вы можете извлечь из этого.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top