/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
#ifndef CTSAUDIO_REMOTEAUDIO_H
#define CTSAUDIO_REMOTEAUDIO_H
#include <map>
#include <utils/Looper.h>
#include <utils/String8.h>
#include <utils/StrongPointer.h>
#include <utils/threads.h>
#include "audio/Buffer.h"
#include "AudioProtocol.h"
#include "ClientSocket.h"
#include "Semaphore.h"
class CommandHandler;
/**
* Tcp communication runs in a separate thread,
* and client can communicate using public APIs
* Assumption: only one command at a time. No other command can come
* while a command is pending.
*/
class RemoteAudio: public android::Thread {
public:
RemoteAudio(ClientSocket& socket);
virtual ~RemoteAudio();
/** launch a thread, and connect to host */
bool init(int port);
bool downloadData(const android::String8 name, android::sp<Buffer>& buffer, int& id);
// <0 : not found
int getDataId(const android::String8& name);
bool startPlayback(bool stereo, int samplingF, int mode, int volume,
int id, int numberRepetition);
void stopPlayback();
bool waitForPlaybackCompletion();
// buffer.getSize() determines number of samples
bool startRecording(bool stereo, int samplingF, int mode, int volume,
android::sp<Buffer>& buffer);
bool waitForRecordingCompletion();
void stopRecording();
bool getDeviceInfo(android::String8& data);
/** should be called before RemoteAudio is destroyed */
void release();
private:
RemoteAudio(const RemoteAudio&);
bool threadLoop();
void wakeClient(bool result);
void cleanup(bool notifyClient);
bool handlePacket();
static int socketRxCallback(int fd, int events, void* data);
class CommandHandler;
void sendCommand(android::sp<android::MessageHandler>& command);
// this is just semaphore wait without any addition
bool waitForCompletion(android::sp<android::MessageHandler>& command, int timeInMSec);
// common code for waitForXXXCompletion
bool waitForPlaybackOrRecordingCompletion(
android::sp<android::MessageHandler>& commandHandler);
// common code for stopXXX
void doStop(android::sp<android::MessageHandler>& commandHandler, AudioProtocol::CommandId id);
CommandHandler* toCommandHandler(android::sp<android::MessageHandler>& command) {
return reinterpret_cast<CommandHandler*>(command.get());
};
private:
bool mExitRequested;
bool mInitResult;
// used only for notifying successful init
Semaphore mInitWait;
enum EventId {
EIdSocket = 1,
};
static const int CLIENT_WAIT_TIMEOUT_MSEC = 2000;
int mPort;
ClientSocket& mSocket;
android::sp<android::Looper> mLooper;
friend class CommandHandler;
class CommandHandler: public android::MessageHandler {
public:
enum ClientCommands {
EExit = 1,
};
CommandHandler(RemoteAudio& thread, int command)
: mThread(thread),
mMessage(command),
mNotifyOnReply(false),
mActive(false) {};
virtual ~CommandHandler() {};
void handleMessage(const android::Message& message);
bool timedWait(int timeInMSec) {
return mClientWait.timedWait(timeInMSec);
};
AudioParam& getParam() {
return mParam;
};
android::Message& getMessage() {
return mMessage;
};
private:
RemoteAudio& mThread;
AudioParam mParam;
Semaphore mClientWait;
android::Mutex mStateLock;
android::Message mMessage;
bool mResult;
bool mNotifyOnReply;
bool mActive;
friend class RemoteAudio;
};
android::sp<android::MessageHandler> mDownloadHandler;
android::sp<android::MessageHandler> mPlaybackHandler;
android::sp<android::MessageHandler> mRecordingHandler;
android::sp<android::MessageHandler> mDeviceInfoHandler;
AudioProtocol* mCmds[AudioProtocol::ECmdLast - AudioProtocol::ECmdStart];
int mDownloadId;
std::map<int, android::sp<Buffer> > mBufferList;
std::map<android::String8, int> mIdMap;
};
#endif // CTSAUDIO_REMOTEAUDIO_H