6

我有一个流式传输 url 可以在我的应用程序中流式传输,并且我还录制了相同的文件以离线收听。我可以在媒体播放器和服务的帮助下流式传输 URL,但现在我正在寻找同一文件的录制逻辑。

如何录制直播并在 SD 卡上保存文件?

4

4 回答 4

4

我假设您不想使用麦克风录制音频流,而是下载原始音频文件,然后您正在寻找的是所谓的渐进式下载,这里有一个很好的使用 MediaController 设置它的教程,基本上你首先开始下载文件,当你下载它时,你用播放器作为数据源在本地读取缓冲文件。

从上面的链接中,您可以使用 StreamingMediaPlayer,原始的 android MediaPlayer 尚不支持来自外部 URL 的流式传输,因此此类通过增量下载内容并在我们在临时存储中获得足够的音频后立即播放来提供伪流式传输功能。

public class StreamingMediaPlayer {

private static final int INTIAL_KB_BUFFER =  96*10/8;//assume 96kbps*10secs/8bits per byte

private TextView textStreamed;

private ImageButton playButton;

private ProgressBar progressBar;

//  Track for display by progressBar
private long mediaLengthInKb, mediaLengthInSeconds;
private int totalKbRead = 0;

// Create Handler to call View updates on the main UI thread.
private final Handler handler = new Handler();

private MediaPlayer     mediaPlayer;

private File downloadingMediaFile; 

private boolean isInterrupted;

private Context context;

private int counter = 0;

public StreamingMediaPlayer(Context  context,TextView textStreamed, ImageButton playButton, Button  streamButton,ProgressBar    progressBar) 
{
    this.context = context;
    this.textStreamed = textStreamed;
    this.playButton = playButton;
    this.progressBar = progressBar;
}

/**  
 * Progressivly download the media to a temporary location and update the MediaPlayer as new content becomes available.
 */  
public void startStreaming(final String mediaUrl, long  mediaLengthInKb, long   mediaLengthInSeconds) throws IOException {

    this.mediaLengthInKb = mediaLengthInKb;
    this.mediaLengthInSeconds = mediaLengthInSeconds;

    Runnable r = new Runnable() {   
        public void run() {   
            try {   
                downloadAudioIncrement(mediaUrl);
            } catch (IOException e) {
                Log.e(getClass().getName(), "Unable to initialize the MediaPlayer for fileUrl=" + mediaUrl, e);
                return;
            }   
        }   
    };   
    new Thread(r).start();
}

/**  
 * Download the url stream to a temporary location and then call the setDataSource  
 * for that local file
 */  
public void downloadAudioIncrement(String mediaUrl) throws IOException {

    URLConnection cn = new URL(mediaUrl).openConnection();   
    cn.connect();   
    InputStream stream = cn.getInputStream();
    if (stream == null) {
        Log.e(getClass().getName(), "Unable to create InputStream for mediaUrl:" + mediaUrl);
    }

    downloadingMediaFile = new File(context.getCacheDir(),"downloadingMedia_" + (counter++) + ".dat");
    FileOutputStream out = new FileOutputStream(downloadingMediaFile);   
    byte buf[] = new byte[16384];
    int totalBytesRead = 0, incrementalBytesRead = 0;
    do {
        int numread = stream.read(buf);   
        if (numread <= 0)   
            break;   
        out.write(buf, 0, numread);
        totalBytesRead += numread;
        incrementalBytesRead += numread;
        totalKbRead = totalBytesRead/1000;

        testMediaBuffer();
        fireDataLoadUpdate();
    } while (validateNotInterrupted());   

    stream.close();
    if (validateNotInterrupted()) {
        fireDataFullyLoaded();
    }
}  

private boolean validateNotInterrupted() {
    if (isInterrupted) {
        if (mediaPlayer != null) {
            mediaPlayer.pause();
            //mediaPlayer.release();
        }
        return false;
    } else {
        return true;
    }
}


/**
 * Test whether we need to transfer buffered data to the MediaPlayer.
 * Interacting with MediaPlayer on non-main UI thread can causes crashes to so perform this using a Handler.
 */  
private void  testMediaBuffer() {
    Runnable updater = new Runnable() {
        public void run() {
            if (mediaPlayer == null) {
                //  Only create the MediaPlayer once we have the minimum buffered data
                if ( totalKbRead >= INTIAL_KB_BUFFER) {
                    try {
                        startMediaPlayer();
                    } catch (Exception e) {
                        Log.e(getClass().getName(), "Error copying buffered conent.", e);               
                    }
                }
            } else if ( mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000 ){ 
                //  NOTE:  The media player has stopped at the end so transfer any existing buffered data
                //  We test for < 1second of data because the media player can stop when there is still
                //  a few milliseconds of data left to play
                transferBufferToMediaPlayer();
            }
        }
    };
    handler.post(updater);
}

private void startMediaPlayer() {
    try {   
        File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");
        moveFile(downloadingMediaFile,bufferedFile);

        Log.e("Player",bufferedFile.length()+"");
        Log.e("Player",bufferedFile.getAbsolutePath());

        mediaPlayer = new MediaPlayer();
        mediaPlayer.setDataSource(bufferedFile.getAbsolutePath());
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mediaPlayer.prepare();
        fireDataPreloadComplete();

    } catch (IOException e) {
        Log.e(getClass().getName(), "Error initializing the MediaPlaer.", e);
        return;
    }   
}

/**
 * Transfer buffered data to the MediaPlayer.
 * Interacting with MediaPlayer on non-main UI thread can causes crashes to so perform this using a Handler.
 */  
private void transferBufferToMediaPlayer() {
    try {
        // First determine if we need to restart the player after transferring data...e.g. perhaps the user pressed pause
        boolean wasPlaying = mediaPlayer.isPlaying();
        int curPosition = mediaPlayer.getCurrentPosition();
        mediaPlayer.pause();

        File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");
        //FileUtils.copyFile(downloadingMediaFile,bufferedFile);

        mediaPlayer = new MediaPlayer();
        mediaPlayer.setDataSource(bufferedFile.getAbsolutePath());
        //mediaPlayer.setAudioStreamType(AudioSystem.STREAM_MUSIC);
        mediaPlayer.prepare();
        mediaPlayer.seekTo(curPosition);

        //  Restart if at end of prior beuffered content or mediaPlayer was previously playing.  
        //  NOTE:  We test for < 1second of data because the media player can stop when there is still
        //  a few milliseconds of data left to play
        boolean atEndOfFile = mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000;
        if (wasPlaying || atEndOfFile){
            mediaPlayer.start();
        }
    }catch (Exception e) {
        Log.e(getClass().getName(), "Error updating to newly loaded content.", e);                  
    }
}

private void fireDataLoadUpdate() {
    Runnable updater = new Runnable() {
        public void run() {
            textStreamed.setText((CharSequence) (totalKbRead + " Kb read"));
            float loadProgress = ((float)totalKbRead/(float)mediaLengthInKb);
            progressBar.setSecondaryProgress((int)(loadProgress*100));
        }
    };
    handler.post(updater);
}

/**
 * We have preloaded enough content and started the MediaPlayer so update the buttons & progress meters.
 */
private void fireDataPreloadComplete() {
    Runnable updater = new Runnable() {
        public void run() {
            mediaPlayer.start();
            startPlayProgressUpdater();
            playButton.setEnabled(true);
            //streamButton.setEnabled(false);
        }
    };
    handler.post(updater);
}

private void fireDataFullyLoaded() {
    Runnable updater = new Runnable() { 
        public void run() {
            transferBufferToMediaPlayer();
            textStreamed.setText((CharSequence) ("Audio full loaded: " + totalKbRead + " Kb read"));
        }
    };
    handler.post(updater);
}

public MediaPlayer getMediaPlayer() {
    return mediaPlayer;
}

public void startPlayProgressUpdater() {
    float progress = (((float)mediaPlayer.getCurrentPosition()/1000)/(float)mediaLengthInSeconds);
    progressBar.setProgress((int)(progress*100));

    if (mediaPlayer.isPlaying()) {
        Runnable notification = new Runnable() {
            public void run() {
                startPlayProgressUpdater();
            }
        };
        handler.postDelayed(notification,1000);
    }
}    

public void interrupt() {
    playButton.setEnabled(false);
    isInterrupted = true;
    validateNotInterrupted();
}

public void moveFile(File   oldLocation, File   newLocation)
throws IOException {

    if ( oldLocation.exists( )) {
        BufferedInputStream  reader = new BufferedInputStream( new FileInputStream(oldLocation) );
        BufferedOutputStream  writer = new BufferedOutputStream( new FileOutputStream(newLocation, false));
        try {
            byte[]  buff = new byte[8192];
            int numChars;
            while ( (numChars = reader.read(  buff, 0, buff.length ) ) != -1) {
                writer.write( buff, 0, numChars );
            }
        } catch( IOException ex ) {
            throw new IOException("IOException when transferring " + oldLocation.getPath() + " to " + newLocation.getPath());
        } finally {
            try {
                if ( reader != null ){
                    writer.close();
                    reader.close();
                }
            } catch( IOException ex ){
                Log.e(getClass().getName(),"Error closing files when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() ); 
            }
        }
    } else {
        throw new IOException("Old location does not exist when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );
    }
}

}

然后你可以像这样轻松地使用它:

private void startStreamingAudio() {
    try { 
        final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);
        if ( audioStreamer != null) {
            audioStreamer.interrupt();
        }
        audioStreamer = new StreamingMediaPlayer(this,textStreamed, playButton, streamButton,progressBar);
        audioStreamer.startStreaming("http://www.pocketjourney.com/downloads/pj/tutorials/audio.mp3",1677, 214);
        //streamButton.setEnabled(false);
    } catch (IOException e) {
        Log.e(getClass().getName(), "Error starting to stream audio.", e);                  
    }
于 2013-07-29T13:07:13.270 回答
2

我认为你的问题在那里解决了:

https://stackoverflow.com/a/5384161/2545832

尝试逐字节操作。它由这个家伙工作。

希望能帮助到你 !

编辑 :

抱歉没看到评论!

于 2013-07-23T12:01:58.253 回答
1

您必须通过本地套接字服务器传递音频流量。在这里查看我的答案:

Android > 4.0:如何录制/捕获内部音频(例如 STREAM_MUSIC)的想法?

于 2013-07-25T06:49:13.307 回答
0

如果您正在处理音频数据,则使用AudioRecord类而不是MediaRecorder类。

有一个在线示例代码,您可以下载并测试您的应用程序。

如前所述,

本文的示例应用程序录制音频并将其保存到SDCard中。该文件将是 WAV 文件,并将以当前毫秒为文件名放置在“/SDCard/AudioRecorder”文件夹中。

检查文章android-audio-recording-part-2/

边注:

如果要将录制的文件保存为mp3格式,则修改源代码文件RecorderActivity.java。在那里你会看到这条线private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".wav";

将其更改为private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".mp3";

或者

您也可以根据应用程序的需要修改变量名称或相关代码。

祝你好运!

于 2013-07-29T08:23:02.360 回答