`
gekie
  • 浏览: 158431 次
  • 性别: Icon_minigender_1
  • 来自: 海口
社区版块
存档分类
最新评论

转:android 实现 流媒体 播放远程mp3文件 代码

 
阅读更多

package com.shadow.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

import com.shadow.service.AudioPlayService.LocalBinder;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

/**
 * MediaPlayer does not yet support streaming from external URLs so this class provides a pseudo-streaming function
 * by downloading the content incrementally & playing as soon as we get enough audio in our temporary storage.
 */
public class StreamingMediaPlayer extends Service{

    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;
    private static Runnable r;
    private static Thread playerThread;
    private LocalBinder localBinder = new LocalBinder();
    private MediaPlayer player;
    private boolean isPause = false;     //播放器是否处于暂停状态
    private boolean isSame = false;      //所点播歌曲是否是当前播放歌曲
    private Integer position = -1;       //设置播放标记
    private List<String> music_name;     //歌曲列表
    private List<String> music_path;
    
     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;
        
        r = new Runnable() {   
            public void run() {   
                try {
                    Log.i("downloadAudioIncrement", "downloadAudioIncrement");
                    downloadAudioIncrement(mediaUrl);
                } catch (IOException e) {
                    Log.e(getClass().getName(), "Unable to initialize the MediaPlayer for fileUrl=" + mediaUrl, e);
                    return;
                }   
            }   
        };   
        playerThread = new Thread(r);
        playerThread.start();
        //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.addRequestProperty("User-Agent","NSPlayer/10.0.0.4072 WMFSDK/10.0");
        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.dat");
        
        // Just in case a prior deletion failed because our code crashed or something, we also delete any previously 
        // downloaded file to ensure we start fresh.  If you use this code, always delete 
        // no longer used downloads else you'll quickly fill up your hard disk memory.  Of course, you can also 
        // store any previously downloaded file in a separate data cache for instant replay if you wanted as well.
        if (downloadingMediaFile.exists()) {
            downloadingMediaFile.delete();
        }

        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");
            
            // We double buffer the data to avoid potential read/write errors that could happen if the 
            // download thread attempted to write at the same time the MediaPlayer was trying to read.
            // For example, we can't guarantee that the MediaPlayer won't open a file for playing and leave it locked while 
            // the media is playing.  This would permanently deadlock the file download.  To avoid such a deadloack, 
            // we move the currently loaded data to a temporary buffer file that we start playing while the remaining 
            // data downloads.  
            moveFile(downloadingMediaFile,bufferedFile);
            
            Log.e(getClass().getName(),"Buffered File path: " + bufferedFile.getAbsolutePath());
            Log.e(getClass().getName(),"Buffered File length: " + bufferedFile.length()+"");
            
            mediaPlayer = createMediaPlayer(bufferedFile);
            
            // We have pre-loaded enough content and started the MediaPlayer so update the buttons & progress meters.
            mediaPlayer.start();
            startPlayProgressUpdater();            
            playButton.setEnabled(true);
        } catch (IOException e) {
            Log.e(getClass().getName(), "Error initializing the MediaPlayer.", e);
            return;
        }   
    }
    
    public void pausePlayer(){
        try {
            getMediaPlayer().pause();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    
    public void startPlayer(){
        getMediaPlayer().start();
    }
    
    public void stopPlayer(){
        getMediaPlayer().stop();
    }
    
    /**
     * 根据文件创建一个mediaplayer对象
     */
    private MediaPlayer createMediaPlayer(File mediaFile)
    throws IOException {
        MediaPlayer mPlayer = new MediaPlayer();
        mPlayer.setOnErrorListener(
                new MediaPlayer.OnErrorListener() {
                    public boolean onError(MediaPlayer mp, int what, int extra) {
                        Log.e(getClass().getName(), "Error in MediaPlayer: (" + what +") with extra (" +extra +")" );
                        return false;
                    }
                });

        //  It appears that for security/permission reasons, it is better to pass a FileDescriptor rather than a direct path to the File.
        //  Also I have seen errors such as "PVMFErrNotSupported" and "Prepare failed.: status=0x1" if a file path String is passed to
        //  setDataSource().  So unless otherwise noted, we use a FileDescriptor here.
        FileInputStream fis = new FileInputStream(mediaFile);
        mPlayer.setDataSource(fis.getFD());
        mPlayer.prepare();
        return mPlayer;
    }

 

 

/**
     * 把缓存转化成mediaplay对象
     * Transfer buffered data to the MediaPlayer.
     * NOTE: Interacting with a MediaPlayer on a non-main UI thread can cause thread-lock and crashes so 
     * this method should always be called 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();
            
            // Copy the currently downloaded content to a new buffered File.  Store the old File for deleting later. 
            File oldBufferedFile = new File(context.getCacheDir(),"playingMedia" + counter + ".dat");
            File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");

            //  This may be the last buffered File so ask that it be delete on exit.  If it's already deleted, then this won't mean anything.  If you want to 
            // keep and track fully downloaded files for later use, write caching code and please send me a copy.
            bufferedFile.deleteOnExit();   
            moveFile(downloadingMediaFile,bufferedFile);

            // Pause the current player now as we are about to create and start a new one.  So far (Android v1.5),
            // this always happens so quickly that the user never realized we've stopped the player and started a new one
            mediaPlayer.pause();

            // Create a new MediaPlayer rather than try to re-prepare the prior one.
            mediaPlayer = createMediaPlayer(bufferedFile);
            mediaPlayer.seekTo(curPosition);
            
            //  Restart if at end of prior buffered 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();
            }

            // Lastly delete the previously playing buffered File as it's no longer needed.
            oldBufferedFile.delete();
            
        }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((totalKbRead + " Kb read"));
                float loadProgress = ((float)totalKbRead/(float)mediaLengthInKb);
                //progressBar.setSecondaryProgress((int)(loadProgress*100));
            }
        };
        handler.post(updater);
    }
    
    private void fireDataFullyLoaded() {
        Runnable updater = new Runnable() { 
            public void run() {
                   transferBufferToMediaPlayer();

                   // Delete the downloaded File as it's now been transferred to the currently playing buffer file.
                   downloadingMediaFile.delete();
                //textStreamed.setText(("Audio full loaded: " + totalKbRead + " Kb read"));
            }
        };
        handler.post(updater);
    }
    
    //TODO 这个方法应该可以控制歌曲的播放
    public MediaPlayer getMediaPlayer() {
        return mediaPlayer;
    }
    
    public void startPlayProgressUpdater() {
        float progress = (((float)mediaPlayer.getCurrentPosition()/1000)/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();
    }
    
    /**
     *  Move the file in oldLocation to newLocation.
     */
    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() );
        }
    }
    
    /**
     * 獲取service中的播放器对象
     * @return  播放器对象
     */
    public MediaPlayer getPlayer() {
        return this.player;
    }
    
    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        /**
         * 1.现在需要的就是做从PlayActivity里获取歌曲列表,和歌曲路径,歌曲手名
         *       并存放到各个集合里
         * 2.之后就是对对这些数组进行处理
         */
        music_name = new ArrayList<String>();
        music_path = new ArrayList<String>();
        String info = intent.getStringExtra("info");
        //songPath = intent.getStringExtra("songPath");
        Toast.makeText(getApplicationContext(), "歌曲播放异常", Toast.LENGTH_SHORT).show();
        player = new MediaPlayer();
        try {
            playMusic(info);
        } catch (Exception e) {
            Toast.makeText(getApplicationContext(), "歌曲播放异常", Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }
    
    //播放音乐
    private void playMusic(String info) throws Exception {
        if ("play".equals(info)) {
            if (isPause) {// 暂停后,继续播放
                player.start();
                isPause = false;
            } else if (isSame) {// 如果现在播放和与所点播歌曲时同一首,继续播放所选歌曲
                player.start();
            } else {// 点播某一首歌曲
                play();
            }
        } else if ("pause".equals(info)) {
            player.pause();// 暂停
            isPause = true;
        } else if ("before".equals(info)) {
            playBefore();// 播放上一首
        } else if ("after".equals(info)) {
            playAfter();// 播放下一首
        }
    }
    private void play() throws Exception {
        //TODO  获取歌曲路径
        
        try {
            Log.i("playtest", "playtest");
        //    myApp.setPlaying_position(position);  //设置歌曲 当前的播放标记
            player.reset();
            //player.setDataSource(songPath);
            player.start();
            //musicName = music_name.get(position);  
        } catch (Exception e) {
            e.printStackTrace();
        }
         
    }
    
    private void playBefore() throws Exception {
        if (position == 0) {
            position = music_name.size() - 1;
        } else {
            position--;
        }
        play();
    }

    private void playAfter() throws Exception {
        if (position == 0) {
            position = music_name.size() + 1;
        } else {
            position++;
        }
        play();
    }
    
    public class LocalBinder extends Binder {
        public StreamingMediaPlayer getService() {
            return StreamingMediaPlayer.this;
        }
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return localBinder;
    }
}
 
分享到:
评论
1 楼 飘零的叶子 2012-10-12  
您好,为啥有的手机可以唱,有的手机不可以呢?

相关推荐

    android 实现 流媒体 播放远程mp3文件 代码

    在Android平台上,流媒体播放远程MP3文件是一个常见的需求,特别是在音乐播放应用或者在线音频服务中。本示例代码提供了一种实现方式,通过下载并缓存一部分音频数据,然后利用`MediaPlayer`进行播放,实现了类似流...

    android 实现流媒体播放远程mp3文件代码pdf

    ### Android 实现流媒体播放远程MP3文件代码详解 #### 一、背景介绍与目标 在Android开发过程中,实现远程音频文件(如MP3)的流式播放是一项常见且实用的功能。本文档将深入探讨一个具体的实现案例,该案例通过...

    Android实现使用流媒体播放远程mp3文件的方法

    在Android平台上,流媒体播放远程mp3文件是一个常见的需求,尤其在音乐应用或者在线音频服务中。本文将详细介绍如何在Android中实现这一功能,包括关键的步骤、使用的类和方法以及一些实现技巧。 首先,Android的...

    Android开发,实现播放本地MP3和播放链接MP3音频

    在Android开发中,实现播放本地MP3和网络MP3音频是一项常见的需求,尤其在音乐类应用或者需要背景音效的应用中。本示例项目“Mp3demo”将详细阐述这一功能的实现步骤和关键技术。 首先,播放本地MP3文件通常涉及的...

    android 实现远程和本地播放MAP3

    在Android中,我们可以使用多种方式来播放MP3文件: 1. **MediaPlayer**:Android系统内置的`MediaPlayer`类是播放音频和视频的基本组件。它支持多种媒体格式,包括MP3。对于本地文件,可以直接使用`MediaPlayer....

    流媒体播放程序、使用说明及部分源码

    流媒体播放程序是一种技术,它允许用户实时观看音频或视频内容,而无需等待整个文件下载完成。这种技术在互联网上广泛使用,因为它提高了用户体验,使用户可以即时观看内容,尤其适用于在线视频平台、直播服务以及...

    Android安卓MP3播放器源码

    `MediaPlayer`是Android中用于播放音频和视频的核心组件,它可以处理各种媒体源,如HTTP、RTSP流媒体、文件或内存中的数据。 2. **URL与IP地址转换**:描述中提到要将URL地址改成本机IP地址,这通常是因为在本地...

    Android代码-音乐播放源码.zip

    同时,实现媒体按钮的远程控制(如耳机上的播放/暂停键)也是必要的,这需要用到`RemoteControlClient`(API 16及以下)或`MediaSession`(API 21及以上)。 7. **权限管理**:考虑到Android的权限模型,音乐播放器...

    Android源码——音乐播放源码.zip

    创建一个MediaService可以实现播放控制并处理系统广播事件。 5. **Intent和BroadcastReceiver**: 为了实现远程控制(如锁屏界面、通知栏)的音乐播放,可以利用Intent和BroadcastReceiver。注册一个...

    Android简易音乐播放器

    在Android平台上开发一款简易音乐播放器,涉及到许多关键的技术点,包括媒体库的访问、音频流处理、UI设计以及动画效果。以下是对这些知识点的详细解释: 1. **媒体库访问**:Android提供了MediaStore类,允许应用...

    android版实现音乐播放器

    例如,`OnCompletionListener`可以监听歌曲播放结束,`OnErrorListener`可以捕获播放错误,`OnPreparedListener`则在媒体文件准备就绪后触发。 4. **UI设计**:音乐播放器通常需要一个友好的用户界面,包括播放/...

    手机远程MP3播放器.zip

    5. **网络连接需求**:由于依赖网络进行流媒体播放,因此,手机远程MP3播放器需要稳定且高速的网络环境。在Wi-Fi环境下,用户可以享受无损音质;而在移动数据下,应用可能会有适应性调整,如降低音频质量以节省流量...

    安卓Android源码——音乐播放器(晴天播放)源码.zip

    MediaPlayer是Android平台上的核心组件,它支持多种音频格式,如MP3、AAC等,并且可以进行流媒体播放。开发者可以通过控制MediaPlayer的状态(如准备、播放、暂停、停止)来实现播放器的基本功能。 接下来,...

    Android平台MP3播放器

    首先,我们要理解MP3播放器的基本功能,它需要能够处理本地存储的音乐文件以及在线流媒体服务。以下是对这个项目的一些详细说明: 1. **本地播放**:在Android设备上,MP3播放器首要的任务是能够读取并播放存储在SD...

    android多媒体例程

    `MediaPlayer`是Android提供的一个系统服务,用于播放各种类型的媒体文件和流媒体。它支持多种音频和视频格式,如MP3、AAC、MP4、3GP等,并且能够处理网络流媒体,使得在应用中集成在线播放成为可能。 下面我们将...

    简单地音乐播放,支持后台播放和远程控制及显示音乐信息

    在IT领域,开发一个能够实现“简单地音乐播放,支持后台播放和远程控制及显示音乐信息”的应用是一项常见的任务。这个应用的核心功能包括音乐播放、后台运行能力以及远程控制,这些功能对于提升用户体验至关重要。 ...

    Android MP3播放器

    这需要使用到Android的网络编程接口,如HttpURLConnection或者OkHttp库来下载或流式播放MP3文件。同时,需要理解HTTP协议和流媒体概念。 **3. Service组件** 为了在后台持续播放音乐,我们需要创建一个Service。...

    应用源码之Wind音乐播放器.zip

    - 可能包含一个`BroadcastReceiver`,监听媒体按钮事件(如耳机按键),实现对音乐播放的远程控制。 通过分析和学习Wind音乐播放器的源码,开发者可以掌握Android应用开发的基本流程,了解多媒体播放、数据存储、...

    android 播放器

    而`ExoPlayer`是Google官方推荐的高级播放器,它具有更强大的自定义能力,支持更多的格式和功能,如DASH和HLS流媒体协议。 2. **音频/视频解码**:Android支持多种编码格式,如MP3、AAC、MP4、FLV等。解码工作通常...

Global site tag (gtag.js) - Google Analytics