捕获电脑的声音放到手机播放

最近笔记本的音响坏了,郁闷啊、纠结中,有一个想法:捕获电脑的声音,这个声音可以是movie的声音、music的声音、或者系统的声音,只要是经过声卡播放的声音,都可以捕获。然后通过usb发送到手机上播放,也可以通过wifi发送到手机播放。

看看怎么做,可以使用微软发布的DirectX SDK,我使用的是DirectX 10 SDK,很多地方可以下载到这个sdk, 大小500M左右。在sdk的目录DirectX 10 SDK\Samples\C++\DirectSound下,有一个例子CaptureSound,CaptureSound是用来捕获声音的,它一面捕获声音,一面写进一个wav的文件里。修改这个例子,把捕获的声音立即发送给手机,可以通过usb发送、或者wifi。

首先设置pc的录音通道,在电脑的托盘上,双击小喇叭,菜单“选项”->“属性”,选择“录音”,只勾选“立体声混音”。看一下效果:

 

转载,请写明出处:http://blog.csdn.net/menghnhhuan/article/details/8281747

usb通信时这样的:

在pc上使用adb命令:adb forward tcp:4626 tcp:4883,在PC上建立4626端口通信数据将被重定向到手机端server的4883端口;然后初始化socket,连接到手机4626端口,进行socket通信。PC端代码如下:

 

DWORD WINAPI usbThreadFunc(LPVOID threadNum)
{
	int length;	
	CString temp;
	if(!initAdb())//adb init
	{
		MessageBox(0, L"初始化手机出错!", L"提示", MB_OK);
		return 0;
	}
	if(!InItClientSock())//socket init
	{
		MessageBox(0, L"初始化IP地址出错!", L"提示", MB_OK);
		return 0;
	}
	if(!USBConnectSock((HWND)threadNum))//connect socket
	{
		MessageBox(0, L"连接IP地址出错!", L"提示", MB_OK);
		return 0;
	}
	//等待连接的时候,连接可能被取消。
	if(clientThreadRun)
	{
	}
	else
	{
		MessageBox(0, L"用户取消!", L"提示", MB_OK);
		return 0;
	}
	SetDlgItemText( (HWND)threadNum, IDC_SOUNDFILE, TEXT("&USB Disconnect") );
	EnableWindow( GetDlgItem( (HWND)threadNum, IDC_RECORD ), TRUE );
	EnableWindow( GetDlgItem( (HWND)threadNum, IDC_BUTTON_WIFI ), FALSE );	
	while(clientThreadRun)
	{
		if( (length = recv(clientSock,(char*)recv_message_client,sizeof(recv_message_client),0))>0)
		{
			memset(recv_message_client, 0, sizeof(recv_message_client));
			LogPrintf(recv_message_client);
		}		
	}
	return 0;
}

 

这里说道最重要的是捕获声音,下面的代码启动了一个线程来处理捕获到的声音:

DWORD WINAPI captureThreadFunc(LPVOID hDlg)
{
	DWORD dwResult;
	while(g_bRecording) 
	{ 
		dwResult = MsgWaitForMultipleObjects( 1, &g_hNotificationEvent, FALSE, INFINITE, QS_ALLEVENTS );
		switch( dwResult )
		{
		case STATUS_WAIT_0://case WAIT_OBJECT_0 + 0:

			RecordCapturedData();
			break;
		}
	}
	return 0;
}

 

在创建捕获声音的设备的时候,会创建一个事件,这个事件就是捕获到一定长度的声音之后(比如2K大小的声音),会发出一个通知,告诉你去处理。上面的线程,就是一直待等待这个事件,然后再去处理捕获到的声音,把声音发送给socket,交给手机处理,代码:

HRESULT RecordCapturedData() 
{
    HRESULT hr;
    VOID*   pbCaptureData    = NULL;
    DWORD   dwCaptureLength;
    VOID*   pbCaptureData2   = NULL;
    DWORD   dwCaptureLength2;
    DWORD   dwReadPos;
    DWORD   dwCapturePos;
    LONG lLockSize;

    if( NULL == g_pDSBCapture )
        return S_FALSE;

    if( FAILED( hr = g_pDSBCapture->GetCurrentPosition( &dwCapturePos, &dwReadPos ) ) )
        return DXTRACE_ERR_MSGBOX( TEXT("GetCurrentPosition"), hr );

    lLockSize = dwReadPos - g_dwNextCaptureOffset;
    if( lLockSize < 0 )
        lLockSize += g_dwCaptureBufferSize;

    // Block align lock size so that we are always write on a boundary
    lLockSize -= (lLockSize % g_dwNotifySize);

    if( lLockSize == 0 )
        return S_FALSE;

    // Lock the capture buffer down
    if( FAILED( hr = g_pDSBCapture->Lock( g_dwNextCaptureOffset, lLockSize, 
                                          &pbCaptureData, &dwCaptureLength, 
                                          &pbCaptureData2, &dwCaptureLength2, 0L ) ) )
        return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );

	
    // Write the data to socket发送给手机
	socketSend(pbCaptureData,dwCaptureLength);
    // Move the capture offset along
    g_dwNextCaptureOffset += dwCaptureLength; 
    g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer

    if( pbCaptureData2 != NULL )
    {
        // Write the data to socket发送给手机
 		socketSend(pbCaptureData2,dwCaptureLength2);

        // Move the capture offset along
        g_dwNextCaptureOffset += dwCaptureLength2; 
        g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer
    }

    // Unlock the capture buffer
    g_pDSBCapture->Unlock( pbCaptureData,  dwCaptureLength, 
                           pbCaptureData2, dwCaptureLength2 );
    return S_OK;
}

 

通过socket发送数据的代码很简单,没有任何处理捕获到的声音数据,就发送给手机了

VOID socketSend(VOID* send_message, int length)
{
	if(clientSockConnect==0)
	{		
		int send_len = length;
		char * buf = (char*)send_message;

		while(send_len>0)
		{		
			int rc = send(clientSock,buf,send_len, 0);//MSG_OOB
			if (rc < 1)//if (rc == SOCKET_ERROR || rc == 0)
			{
				break;
			}	
			send_len -= rc;
			buf += rc;
		}
		buf = NULL;
	}
}


手机端的代码如下,注意手机上audioTrack的设置:44100,AudioFormat.CHANNEL_CONFIGURATION_STEREO,AudioFormat.ENCODING_PCM_16BIT。在启动电脑捕获声音的时候也要同样的设置,否则播放的声音是杂音:

public class TcpConnect extends Thread {
	private ServerSocket mServerSocket;
	private Socket mClient;
	private Handler mHandler;
	private boolean running = false;
	private boolean palying = false;

	private int audioPlayBufSize;
	private AudioTrack audioTrack;
	private static final int frequency = 44100;
	private static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
	private static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

	private ArrayList<byte[]> inBuf = new ArrayList<byte[]>();

	public TcpConnect(Handler handler) {
		mHandler = handler;

		audioPlayBufSize = AudioTrack.getMinBufferSize(frequency,
				channelConfiguration, audioEncoding);
		audioTrack = new AudioTrack(
				AudioManager.STREAM_MUSIC,// .STREAM_RING,//.STREAM_MUSIC,
				frequency, channelConfiguration, audioEncoding,
				audioPlayBufSize, AudioTrack.MODE_STREAM);
		audioTrack.setStereoVolume(1.0f, 1.0f);
		Log.d("playPCAudio", "audioPlayBufSize: " + audioPlayBufSize);

		palying = false;
		inBuf.clear();
	}

	public void run() {
		try {
			mServerSocket = new ServerSocket(4883);

			System.out.println("TcpConnect" + "开始监听");
			mClient = mServerSocket.accept();
			System.out.println("TcpConnect" + "检测到有连接");
			InputStream is = mClient.getInputStream();

			running = true;
			int readLen = 0;
			byte[] readBuf = new byte[audioPlayBufSize];

			System.out.println("TcpConnect" + "接收");
			playThread palyt = new playThread();
			palyt.setPriority(Thread.MAX_PRIORITY);
			palyt.start();

			while (running) {
				if ((readLen = is.read(readBuf, 0, audioPlayBufSize)) > 0) {
					byte[] tmpBuf = new byte[readLen];
					System.arraycopy(readBuf, 0, tmpBuf, 0, readLen);
					synchronized (inBuf) {
						inBuf.add(tmpBuf);
					}
				}
			}
		} catch (Exception e) {
			System.out.println("TcpConnect TCP error:" + e.getMessage());
		}
		System.out.println("TcpConnect over");
	}

	class playThread extends Thread {

		public playThread() {
		}
		public void run() {
			audioTrack.play();
			palying = true;

			while (running) {
				ArrayList<byte[]> buf = new ArrayList<byte[]>();
				buf.clear();
				synchronized (inBuf) {
					if (inBuf.size() == 0)
						continue;
					buf = (ArrayList<byte[]>) inBuf.clone();
					inBuf.clear();
				}
				for (int i = 0; i < buf.size(); i++) {
					byte[] tmpBuf = buf.get(i);
					audioTrack.write(tmpBuf, 0, tmpBuf.length);
				}
			}
			if (palying) {
				audioTrack.stop();
				audioTrack.release();
				palying = false;
			}
		}
	}
}

我的博客:http://blog.csdn.net/menghnhhuan

PC和手机的代码下载地址:

http://download.csdn.net/detail/menghnhhuan/4873008

大家在捕获声音的时候,可能会出现杂音,需要调试,请留言。

有需要的同学在这里下载:http://pan.baidu.com/s/17W5Tt
已经上传到百度网盘,里面有使用说明。CSDN的下载链接需要积分,无法修改。
 

  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 34
    评论
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值