/* ** ** Copyright 2008, 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. */ //#define LOG_NDEBUG 0 #define LOG_TAG "IMediaRecorder" #include <inttypes.h> #include <unistd.h> #include <utils/Log.h> #include <binder/Parcel.h> #include <camera/android/hardware/ICamera.h> #include <camera/ICameraRecordingProxy.h> #include <media/IMediaRecorderClient.h> #include <media/IMediaRecorder.h> #include <gui/Surface.h> #include <gui/IGraphicBufferProducer.h> #include <media/stagefright/PersistentSurface.h> namespace android { enum { RELEASE = IBinder::FIRST_CALL_TRANSACTION, INIT, CLOSE, SET_INPUT_SURFACE, QUERY_SURFACE_MEDIASOURCE, RESET, STOP, START, PREPARE, GET_MAX_AMPLITUDE, SET_VIDEO_SOURCE, SET_AUDIO_SOURCE, SET_OUTPUT_FORMAT, SET_VIDEO_ENCODER, SET_AUDIO_ENCODER, SET_OUTPUT_FILE_FD, SET_NEXT_OUTPUT_FILE_FD, SET_VIDEO_SIZE, SET_VIDEO_FRAMERATE, SET_PARAMETERS, SET_PREVIEW_SURFACE, SET_CAMERA, SET_LISTENER, SET_CLIENT_NAME, PAUSE, RESUME, GET_METRICS, SET_INPUT_DEVICE, GET_ROUTED_DEVICE_ID, ENABLE_AUDIO_DEVICE_CALLBACK, GET_ACTIVE_MICROPHONES, GET_PORT_ID, SET_PREFERRED_MICROPHONE_DIRECTION, SET_PREFERRED_MICROPHONE_FIELD_DIMENSION }; class BpMediaRecorder: public BpInterface<IMediaRecorder> { public: explicit BpMediaRecorder(const sp<IBinder>& impl) : BpInterface<IMediaRecorder>(impl) { } status_t setCamera(const sp<hardware::ICamera>& camera, const sp<ICameraRecordingProxy>& proxy) { ALOGV("setCamera(%p,%p)", camera.get(), proxy.get()); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(camera)); data.writeStrongBinder(IInterface::asBinder(proxy)); remote()->transact(SET_CAMERA, data, &reply); return reply.readInt32(); } status_t setInputSurface(const sp<PersistentSurface>& surface) { ALOGV("setInputSurface(%p)", surface.get()); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); surface->writeToParcel(&data); remote()->transact(SET_INPUT_SURFACE, data, &reply); return reply.readInt32(); } sp<IGraphicBufferProducer> querySurfaceMediaSource() { ALOGV("Query SurfaceMediaSource"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); remote()->transact(QUERY_SURFACE_MEDIASOURCE, data, &reply); int returnedNull = reply.readInt32(); if (returnedNull) { return NULL; } return interface_cast<IGraphicBufferProducer>(reply.readStrongBinder()); } status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface) { ALOGV("setPreviewSurface(%p)", surface.get()); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(surface)); remote()->transact(SET_PREVIEW_SURFACE, data, &reply); return reply.readInt32(); } status_t init() { ALOGV("init"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); remote()->transact(INIT, data, &reply); return reply.readInt32(); } status_t setVideoSource(int vs) { ALOGV("setVideoSource(%d)", vs); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeInt32(vs); remote()->transact(SET_VIDEO_SOURCE, data, &reply); return reply.readInt32(); } status_t setAudioSource(int as) { ALOGV("setAudioSource(%d)", as); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeInt32(as); remote()->transact(SET_AUDIO_SOURCE, data, &reply); return reply.readInt32(); } status_t setOutputFormat(int of) { ALOGV("setOutputFormat(%d)", of); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeInt32(of); remote()->transact(SET_OUTPUT_FORMAT, data, &reply); return reply.readInt32(); } status_t setVideoEncoder(int ve) { ALOGV("setVideoEncoder(%d)", ve); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeInt32(ve); remote()->transact(SET_VIDEO_ENCODER, data, &reply); return reply.readInt32(); } status_t setAudioEncoder(int ae) { ALOGV("setAudioEncoder(%d)", ae); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeInt32(ae); remote()->transact(SET_AUDIO_ENCODER, data, &reply); return reply.readInt32(); } status_t setOutputFile(int fd) { ALOGV("setOutputFile(%d)", fd); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeFileDescriptor(fd); remote()->transact(SET_OUTPUT_FILE_FD, data, &reply); return reply.readInt32(); } status_t setNextOutputFile(int fd) { ALOGV("setNextOutputFile(%d)", fd); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeFileDescriptor(fd); remote()->transact(SET_NEXT_OUTPUT_FILE_FD, data, &reply); return reply.readInt32(); } status_t setVideoSize(int width, int height) { ALOGV("setVideoSize(%dx%d)", width, height); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeInt32(width); data.writeInt32(height); remote()->transact(SET_VIDEO_SIZE, data, &reply); return reply.readInt32(); } status_t setVideoFrameRate(int frames_per_second) { ALOGV("setVideoFrameRate(%d)", frames_per_second); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeInt32(frames_per_second); remote()->transact(SET_VIDEO_FRAMERATE, data, &reply); return reply.readInt32(); } status_t setParameters(const String8& params) { ALOGV("setParameter(%s)", params.string()); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeString8(params); remote()->transact(SET_PARAMETERS, data, &reply); return reply.readInt32(); } status_t setListener(const sp<IMediaRecorderClient>& listener) { ALOGV("setListener(%p)", listener.get()); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(listener)); remote()->transact(SET_LISTENER, data, &reply); return reply.readInt32(); } status_t setClientName(const String16& clientName) { ALOGV("setClientName(%s)", String8(clientName).string()); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeString16(clientName); remote()->transact(SET_CLIENT_NAME, data, &reply); return reply.readInt32(); } status_t prepare() { ALOGV("prepare"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); remote()->transact(PREPARE, data, &reply); return reply.readInt32(); } status_t getMaxAmplitude(int* max) { ALOGV("getMaxAmplitude"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); remote()->transact(GET_MAX_AMPLITUDE, data, &reply); *max = reply.readInt32(); return reply.readInt32(); } status_t getMetrics(Parcel* reply) { ALOGV("getMetrics"); Parcel data; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); status_t ret = remote()->transact(GET_METRICS, data, reply); if (ret == NO_ERROR) { return OK; } return UNKNOWN_ERROR; } status_t start() { ALOGV("start"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); remote()->transact(START, data, &reply); return reply.readInt32(); } status_t stop() { ALOGV("stop"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); remote()->transact(STOP, data, &reply); return reply.readInt32(); } status_t reset() { ALOGV("reset"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); remote()->transact(RESET, data, &reply); return reply.readInt32(); } status_t pause() { ALOGV("pause"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); remote()->transact(PAUSE, data, &reply); return reply.readInt32(); } status_t resume() { ALOGV("resume"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); remote()->transact(RESUME, data, &reply); return reply.readInt32(); } status_t close() { ALOGV("close"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); remote()->transact(CLOSE, data, &reply); return reply.readInt32(); } status_t release() { ALOGV("release"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); remote()->transact(RELEASE, data, &reply); return reply.readInt32(); } status_t setInputDevice(audio_port_handle_t deviceId) { ALOGV("setInputDevice"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeInt32(deviceId); status_t status = remote()->transact(SET_INPUT_DEVICE, data, &reply); if (status != OK) { ALOGE("setInputDevice binder call failed: %d", status); return status; } return reply.readInt32();; } audio_port_handle_t getRoutedDeviceId(audio_port_handle_t *deviceId) { ALOGV("getRoutedDeviceId"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); status_t status = remote()->transact(GET_ROUTED_DEVICE_ID, data, &reply); if (status != OK) { ALOGE("getRoutedDeviceid binder call failed: %d", status); *deviceId = AUDIO_PORT_HANDLE_NONE; return status; } status = reply.readInt32(); if (status != NO_ERROR) { *deviceId = AUDIO_PORT_HANDLE_NONE; } else { *deviceId = reply.readInt32(); } return status; } status_t enableAudioDeviceCallback(bool enabled) { ALOGV("enableAudioDeviceCallback"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeBool(enabled); status_t status = remote()->transact(ENABLE_AUDIO_DEVICE_CALLBACK, data, &reply); if (status != OK) { ALOGE("enableAudioDeviceCallback binder call failed: %d, %d", enabled, status); return status; } return reply.readInt32(); } status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones) { ALOGV("getActiveMicrophones"); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); status_t status = remote()->transact(GET_ACTIVE_MICROPHONES, data, &reply); if (status != OK || (status = (status_t)reply.readInt32()) != NO_ERROR) { return status; } status = reply.readParcelableVector(activeMicrophones); return status; } status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction) { ALOGV("setPreferredMicrophoneDirection(%d)", direction); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeInt32(direction); status_t status = remote()->transact(SET_PREFERRED_MICROPHONE_DIRECTION, data, &reply); return status == NO_ERROR ? (status_t)reply.readInt32() : status; } status_t setPreferredMicrophoneFieldDimension(float zoom) { ALOGV("setPreferredMicrophoneFieldDimension(%f)", zoom); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeFloat(zoom); status_t status = remote()->transact(SET_PREFERRED_MICROPHONE_FIELD_DIMENSION, data, &reply); return status == NO_ERROR ? (status_t)reply.readInt32() : status; } status_t getPortId(audio_port_handle_t *portId) { ALOGV("getPortId"); if (portId == nullptr) { return BAD_VALUE; } Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); status_t status = remote()->transact(GET_PORT_ID, data, &reply); if (status != OK || (status = (status_t)reply.readInt32()) != NO_ERROR) { *portId = AUDIO_PORT_HANDLE_NONE; return status; } *portId = (audio_port_handle_t)reply.readInt32(); return NO_ERROR; } }; IMPLEMENT_META_INTERFACE(MediaRecorder, "android.media.IMediaRecorder"); // ---------------------------------------------------------------------- status_t BnMediaRecorder::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case RELEASE: { ALOGV("RELEASE"); CHECK_INTERFACE(IMediaRecorder, data, reply); reply->writeInt32(release()); return NO_ERROR; } break; case INIT: { ALOGV("INIT"); CHECK_INTERFACE(IMediaRecorder, data, reply); reply->writeInt32(init()); return NO_ERROR; } break; case CLOSE: { ALOGV("CLOSE"); CHECK_INTERFACE(IMediaRecorder, data, reply); reply->writeInt32(close()); return NO_ERROR; } break; case RESET: { ALOGV("RESET"); CHECK_INTERFACE(IMediaRecorder, data, reply); reply->writeInt32(reset()); return NO_ERROR; } break; case STOP: { ALOGV("STOP"); CHECK_INTERFACE(IMediaRecorder, data, reply); reply->writeInt32(stop()); return NO_ERROR; } break; case START: { ALOGV("START"); CHECK_INTERFACE(IMediaRecorder, data, reply); reply->writeInt32(start()); return NO_ERROR; } break; case PAUSE: { ALOGV("PAUSE"); CHECK_INTERFACE(IMediaRecorder, data, reply); reply->writeInt32(pause()); return NO_ERROR; } break; case RESUME: { ALOGV("RESUME"); CHECK_INTERFACE(IMediaRecorder, data, reply); reply->writeInt32(resume()); return NO_ERROR; } break; case PREPARE: { ALOGV("PREPARE"); CHECK_INTERFACE(IMediaRecorder, data, reply); reply->writeInt32(prepare()); return NO_ERROR; } break; case GET_MAX_AMPLITUDE: { ALOGV("GET_MAX_AMPLITUDE"); CHECK_INTERFACE(IMediaRecorder, data, reply); int max = 0; status_t ret = getMaxAmplitude(&max); reply->writeInt32(max); reply->writeInt32(ret); return NO_ERROR; } break; case GET_METRICS: { ALOGV("GET_METRICS"); status_t ret = getMetrics(reply); return ret; } break; case SET_VIDEO_SOURCE: { ALOGV("SET_VIDEO_SOURCE"); CHECK_INTERFACE(IMediaRecorder, data, reply); int vs = data.readInt32(); reply->writeInt32(setVideoSource(vs)); return NO_ERROR; } break; case SET_AUDIO_SOURCE: { ALOGV("SET_AUDIO_SOURCE"); CHECK_INTERFACE(IMediaRecorder, data, reply); int as = data.readInt32(); reply->writeInt32(setAudioSource(as)); return NO_ERROR; } break; case SET_OUTPUT_FORMAT: { ALOGV("SET_OUTPUT_FORMAT"); CHECK_INTERFACE(IMediaRecorder, data, reply); int of = data.readInt32(); reply->writeInt32(setOutputFormat(of)); return NO_ERROR; } break; case SET_VIDEO_ENCODER: { ALOGV("SET_VIDEO_ENCODER"); CHECK_INTERFACE(IMediaRecorder, data, reply); int ve = data.readInt32(); reply->writeInt32(setVideoEncoder(ve)); return NO_ERROR; } break; case SET_AUDIO_ENCODER: { ALOGV("SET_AUDIO_ENCODER"); CHECK_INTERFACE(IMediaRecorder, data, reply); int ae = data.readInt32(); reply->writeInt32(setAudioEncoder(ae)); return NO_ERROR; } break; case SET_OUTPUT_FILE_FD: { ALOGV("SET_OUTPUT_FILE_FD"); CHECK_INTERFACE(IMediaRecorder, data, reply); int fd = dup(data.readFileDescriptor()); reply->writeInt32(setOutputFile(fd)); ::close(fd); return NO_ERROR; } break; case SET_NEXT_OUTPUT_FILE_FD: { ALOGV("SET_NEXT_OUTPUT_FILE_FD"); CHECK_INTERFACE(IMediaRecorder, data, reply); int fd = dup(data.readFileDescriptor()); reply->writeInt32(setNextOutputFile(fd)); ::close(fd); return NO_ERROR; } break; case SET_VIDEO_SIZE: { ALOGV("SET_VIDEO_SIZE"); CHECK_INTERFACE(IMediaRecorder, data, reply); int width = data.readInt32(); int height = data.readInt32(); reply->writeInt32(setVideoSize(width, height)); return NO_ERROR; } break; case SET_VIDEO_FRAMERATE: { ALOGV("SET_VIDEO_FRAMERATE"); CHECK_INTERFACE(IMediaRecorder, data, reply); int frames_per_second = data.readInt32(); reply->writeInt32(setVideoFrameRate(frames_per_second)); return NO_ERROR; } break; case SET_PARAMETERS: { ALOGV("SET_PARAMETER"); CHECK_INTERFACE(IMediaRecorder, data, reply); reply->writeInt32(setParameters(data.readString8())); return NO_ERROR; } break; case SET_LISTENER: { ALOGV("SET_LISTENER"); CHECK_INTERFACE(IMediaRecorder, data, reply); sp<IMediaRecorderClient> listener = interface_cast<IMediaRecorderClient>(data.readStrongBinder()); reply->writeInt32(setListener(listener)); return NO_ERROR; } break; case SET_CLIENT_NAME: { ALOGV("SET_CLIENT_NAME"); CHECK_INTERFACE(IMediaRecorder, data, reply); reply->writeInt32(setClientName(data.readString16())); return NO_ERROR; } case SET_PREVIEW_SURFACE: { ALOGV("SET_PREVIEW_SURFACE"); CHECK_INTERFACE(IMediaRecorder, data, reply); sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>( data.readStrongBinder()); reply->writeInt32(setPreviewSurface(surface)); return NO_ERROR; } break; case SET_CAMERA: { ALOGV("SET_CAMERA"); CHECK_INTERFACE(IMediaRecorder, data, reply); sp<hardware::ICamera> camera = interface_cast<hardware::ICamera>(data.readStrongBinder()); sp<ICameraRecordingProxy> proxy = interface_cast<ICameraRecordingProxy>(data.readStrongBinder()); reply->writeInt32(setCamera(camera, proxy)); return NO_ERROR; } break; case SET_INPUT_SURFACE: { ALOGV("SET_INPUT_SURFACE"); CHECK_INTERFACE(IMediaRecorder, data, reply); sp<PersistentSurface> surface = new PersistentSurface(); surface->readFromParcel(&data); reply->writeInt32(setInputSurface(surface)); return NO_ERROR; } break; case QUERY_SURFACE_MEDIASOURCE: { ALOGV("QUERY_SURFACE_MEDIASOURCE"); CHECK_INTERFACE(IMediaRecorder, data, reply); // call the mediaserver side to create // a surfacemediasource sp<IGraphicBufferProducer> surfaceMediaSource = querySurfaceMediaSource(); // The mediaserver might have failed to create a source int returnedNull= (surfaceMediaSource == NULL) ? 1 : 0 ; reply->writeInt32(returnedNull); if (!returnedNull) { reply->writeStrongBinder(IInterface::asBinder(surfaceMediaSource)); } return NO_ERROR; } break; case SET_INPUT_DEVICE: { ALOGV("SET_INPUT_DEVICE"); CHECK_INTERFACE(IMediaRecorder, data, reply); audio_port_handle_t deviceId; status_t status = data.readInt32(&deviceId); if (status == NO_ERROR) { reply->writeInt32(setInputDevice(deviceId)); } else { reply->writeInt32(BAD_VALUE); } return NO_ERROR; } break; case GET_ROUTED_DEVICE_ID: { ALOGV("GET_ROUTED_DEVICE_ID"); CHECK_INTERFACE(IMediaRecorder, data, reply); audio_port_handle_t deviceId; status_t status = getRoutedDeviceId(&deviceId); reply->writeInt32(status); if (status == NO_ERROR) { reply->writeInt32(deviceId); } return NO_ERROR; } break; case ENABLE_AUDIO_DEVICE_CALLBACK: { ALOGV("ENABLE_AUDIO_DEVICE_CALLBACK"); CHECK_INTERFACE(IMediaRecorder, data, reply); bool enabled; status_t status = data.readBool(&enabled); if (status == NO_ERROR) { reply->writeInt32(enableAudioDeviceCallback(enabled)); } else { reply->writeInt32(BAD_VALUE); } return NO_ERROR; } break; case GET_ACTIVE_MICROPHONES: { ALOGV("GET_ACTIVE_MICROPHONES"); CHECK_INTERFACE(IMediaRecorder, data, reply); std::vector<media::MicrophoneInfo> activeMicrophones; status_t status = getActiveMicrophones(&activeMicrophones); reply->writeInt32(status); if (status != NO_ERROR) { return NO_ERROR; } reply->writeParcelableVector(activeMicrophones); return NO_ERROR; } case GET_PORT_ID: { ALOGV("GET_PORT_ID"); CHECK_INTERFACE(IMediaRecorder, data, reply); audio_port_handle_t portId; status_t status = getPortId(&portId); reply->writeInt32(status); if (status == NO_ERROR) { reply->writeInt32(portId); } return NO_ERROR; } case SET_PREFERRED_MICROPHONE_DIRECTION: { ALOGV("SET_PREFERRED_MICROPHONE_DIRECTION"); CHECK_INTERFACE(IMediaRecorder, data, reply); int direction = data.readInt32(); status_t status = setPreferredMicrophoneDirection( static_cast<audio_microphone_direction_t>(direction)); reply->writeInt32(status); return NO_ERROR; } case SET_PREFERRED_MICROPHONE_FIELD_DIMENSION: { ALOGV("SET_MICROPHONE_FIELD_DIMENSION"); CHECK_INTERFACE(IMediaRecorder, data, reply); float zoom = data.readFloat(); status_t status = setPreferredMicrophoneFieldDimension(zoom); reply->writeInt32(status); return NO_ERROR; } default: return BBinder::onTransact(code, data, reply, flags); } } // ---------------------------------------------------------------------------- } // namespace android