GVKun编程网logo

android – Kivy Play Audio不工作(android audiomanager)

14

在这篇文章中,我们将带领您了解android–KivyPlayAudio不工作的全貌,包括androidaudiomanager的相关情况。同时,我们还将为您介绍有关(OK)Androidgraphi

在这篇文章中,我们将带领您了解android – Kivy Play Audio不工作的全貌,包括android audiomanager的相关情况。同时,我们还将为您介绍有关(OK) Android graphic (12)—display 上层相关概念、关系 - mLogicalDisplays.get (Display.DEFAULT_DISPLAY)、Android apk 在 Android Studio 测试中非常完美,但在 Google Play 封闭测试中失败、Android Audio:AudioTrack构造函数分析、Android audioManager解决MediaPlayer AudioTrack 调节音量问的知识,以帮助您更好地理解这个主题。

本文目录一览:

android – Kivy Play Audio不工作(android audiomanager)

android – Kivy Play Audio不工作(android audiomanager)

我试图运行Kivy的音频示例找到 here.具体的例子如下:

sound = SoundLoader.load(filename=''test.wav'')
if not sound:
    # unable to load this sound ?
    pass
else:
    # sound loaded,let''s play!
    sound.play()

但是,当我尝试在我的目录中播放任何.wav文件时,我只会听到咔嗒声或砰砰声.我尝试过使用不同的.wav文件并遇到同样的问题.我还试图通过使用长度函数打印出声音的长度,但由于某种原因它返回0.你们的任何反馈或意见?再次感谢.

解决方法

不能只是看看上面你在应用程序中实现它的代码片段或者出了什么问题.

在你的Kivy安装目录下的examples目录中应该有一个更复杂的example应该清理如何使用SoundLoader.

希望有所帮助.

(OK) Android graphic (12)—display 上层相关概念、关系 - mLogicalDisplays.get (Display.DEFAULT_DISPLAY)

(OK) Android graphic (12)—display 上层相关概念、关系 - mLogicalDisplays.get (Display.DEFAULT_DISPLAY)


http://blog.csdn.net/lewif/article/details/50827430


涉及的 java 类

DisplayManagerService

Manages attached displays.
The DisplayManagerService manages the global lifecycle of displays,
decides how to configure logical displays based on the physical display devices currently
attached, sends notifications to the system and to applications when the state
changes, and so on.
The display manager service relies on a collection of DisplayAdapter components,
for discovering and configuring physical display devices attached to the system.
There are separate display adapters for each manner that devices are attached:
one display adapter for built-in local displays, one for simulated non-functional
displays when the system is headless, one for simulated overlay displays used for
development, one for wifi displays, etc.
Display adapters are only weakly coupled to the display manager service.
Display adapters communicate changes in display device state to the display manager
service asynchronously via a DisplayAdapter.Listener registered
by the display manager service.  This separation of concerns is important for
two main reasons.  First, it neatly encapsulates the responsibilities of these
two classes: display adapters handle individual display devices whereas
the display manager service handles the global state.  Second, it eliminates
the potential for deadlocks resulting from asynchronous display device discovery.

DisplayAdapter

A display adapter makes zero or more display devices available to the system
and provides facilities for discovering when displays are connected or disconnected.
For now, all display adapters are registered in the system server but
in principle it could be done from other processes.

现在支持的 4 种 Adapter,分别对应不同类型的 display。

1.LocalDisplayAdapter
A display adapter for the local displays managed by Surface Flinger
2.WifiDisplayAdapter
Connects to Wifi displays that implement the Miracast protocol.
This class is responsible for connecting to Wifi displays and mediating
the interactions between Media Server, Surface Flinger and the Display Manager Service.
3.VirtualDisplayAdapter
4.OverlayDisplayAdapter

DisplayDevice

 Represents a physical display device such as the built-in display an external monitor, or a WiFi display.
WifiDisplayDevice
VirtualDisplayDevice
OverlayDisplayDevice
LocalDisplayDevice

DisplayManagerGlobal

Manager communication with the display manager service on behalf of an application process.

DisplayManager

Manages the properties of attached displays.

LogicalDisplay

Describes how a logical display is configured.
At this time, we only support logical displays that are coupled to a particular
primary display device from which the logical display derives its basic properties
such as its size, density and refresh rate.
A logical display may be mirrored onto multiple display devices in addition to its
primary display device.  Note that the contents of a logical display may not
always be visible, even on its primary display device, such as in the case where
the primary display device is currently mirroring content from a different
logical display.
Note: The display manager architecture does not actually require logical displays
to be associated with any individual display device.  Logical displays and
display devices are orthogonal concepts.  Some mapping will exist between
logical displays and display devices but it can be many-to-many and
and some might have no relation at all.

Display

Provides information about the size and density of a logical display.

DisplayContent

Utility class for keeping track of the WindowStates and other pertinent contents of a particular Display.

DisplayInfo

Describes the characteristics of a particular logical display.

类之间的关系

以添加系统 built in display 为例,下面是各个类之间的关系图,

这里写图片描述

其中,LocalDisplayDevice 中的 mPhys 是向 surface flinger 获取的 display 的硬件相关属性,而 mDisplayToken 是 surfacefinger 中为 display 创建的 new BBinder 对应的代理对象。

默认屏幕的上层初始化分析

1.
systemserver.Java

/*--------------systemserver.java---------------------------*/
    // 专门为window manager创建了一个handler thread
    // Create a handler thread just for the window manager to enjoy.
        HandlerThread wmHandlerThread = new HandlerThread("WindowManager");
        wmHandlerThread.start();
        //创建一个window manager的Handler(looper是wmHandlerThread线程的)
        Handler wmHandler = new Handler(wmHandlerThread.getLooper());
        wmHandler.post(new Runnable() {
            @Override
            public void run() {
                //Looper.myLooper().setMessageLogging(new LogPrinter(
                //        android.util.Log.DEBUG, TAG, android.util.Log.LOG_ID_SYSTEM));
                android.os.Process.setThreadPriority(
                        android.os.Process.THREAD_PRIORITY_DISPLAY);
                android.os.Process.setCanSelfBackground(false);

                // For debug builds, log event loop stalls to dropbox for analysis.
                if (StrictMode.conditionallyEnableDebugLogging()) {
                    Slog.i(TAG, "Enabled StrictMode logging for WM Looper");
                }
            }
        });
/*--------------systemserver.java---------------------------*/
    // DisplayManagerService display = null;
    // 新建DisplayManagerService服务
        Slog.i(TAG, "Display Manager");
            display = new DisplayManagerService(context, wmHandler);
            ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);
         //需要等待第一个display初始化完成后,才继续进行,否则一直循环
        if (!display.waitForDefaultDisplay()) {
                reportWtf("Timeout waiting for default display to be initialized.",
                        new Throwable());
            }
/*--------------DisplayManagerService.java---------------------------*/
    // 在mSyncRoot wait,直到mLogicalDisplays.get(Display.DEFAULT_DISPLAY)不为null
    // 即有地方添加了默认display的LogicalDisplay
    /**
     * Pauses the boot process to wait for the first display to be initialized.
     */
    public boolean waitForDefaultDisplay() {
        synchronized (mSyncRoot) {
            long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
            while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
                long delay = timeout - SystemClock.uptimeMillis();
                if (delay <= 0) {
                    return false;
                }
                if (DEBUG) {
                    Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
                }
                try {
                    mSyncRoot.wait(delay);
                } catch (InterruptedException ex) {
                }
            }
        }
        return true;
    }
/*--------------DisplayManagerService.java---------------------------*/
   public DisplayManagerService(Context context, Handler mainHandler) {
        mContext = context;
        mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
    //新建个DisplayManagerHandler
        mHandler = new DisplayManagerHandler(mainHandler.getLooper());
        mUiHandler = UiThread.getHandler();
        //新建个DisplayAdapterListener
        mDisplayAdapterListener = new DisplayAdapterListener();
        //persist.demo.singledisplay是只创建默认display的logical display
        mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);

        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
    }

DisplayManagerHandler 的消息处理函数,

/*--------------DisplayManagerService.java---------------------------*/
private final class DisplayManagerHandler extends Handler {
        public DisplayManagerHandler(Looper looper) {
            super(looper, null, true /*async*/);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
                    registerDefaultDisplayAdapter();
                    break;

                case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
                    registerAdditionalDisplayAdapters();
                    break;

                case MSG_DELIVER_DISPLAY_EVENT:
                    deliverDisplayEvent(msg.arg1, msg.arg2);
                    break;

                case MSG_REQUEST_TRAVERSAL:
                    mWindowManagerFuncs.requestTraversal();
                    break;

                case MSG_UPDATE_VIEWPORT: {
                    synchronized (mSyncRoot) {
                        mTempDefaultViewport.copyFrom(mDefaultViewport);
                        mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
                    }
                    mInputManagerFuncs.setDisplayViewports(
                            mTempDefaultViewport, mTempExternalTouchViewport);
                    break;
                }
            }
        }
    }

DisplayAdapterListener 类,

/*--------------DisplayManagerService.java---------------------------*/
    private final class DisplayAdapterListener implements DisplayAdapter.Listener {
        @Override
        public void onDisplayDeviceEvent(DisplayDevice device, int event) {
            switch (event) {
                case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
                    handleDisplayDeviceAdded(device);
                    break;

                case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
                    handleDisplayDeviceChanged(device);
                    break;

                case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
                    handleDisplayDeviceRemoved(device);
                    break;
            }
        }

        @Override
        public void onTraversalRequested() {
            synchronized (mSyncRoot) {
                scheduleTraversalLocked(false);
            }
        }
    }
mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
/* ro.config.headless
    系统中判断ro.config.headless的总共有几个地方
    a、SurfaceControl.java在构造函数中判断如果是headless设备则抛出异常,说明headless的设备不应该构造任何显示画面
    b、在SystemUI中判断headless为true的情况下不启动WallpaperManagerService和SystemUIService
    c、在PhoneWindowManager的systemReady中判断headless为true的情况下不起动KeyguardServiceDelegate,不显示启动提示消息,屏蔽滑盖(lid)状态,屏蔽一些按键
    d、DisplayManagerService在创建默认显示设备的时候(registerDefaultDisplayAdapter)判断headless为true的情况下创建的是HeadlessDisplayAdapter而非LocalDisplayAdapter,前者并没有通过SurfaceFlinger.getBuiltInDisplay获取一个对应的DisplayDevice,也就是说上层的默认显示设备是空
    e、ActivityManagerService在startHomeActivityLocked断headless为true的情况下不启动HomeActivity,不能启动Activity,不能重启挂掉的进程(即使是persistent),不能更新屏幕配置。
*/

mHandler 的 MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER 处理函数为,

/*--------------DisplayManagerService.java---------------------------*/
    private void registerDefaultDisplayAdapter() {
        // Register default display adapter.
        synchronized (mSyncRoot) {
            if (mHeadless) {
                registerDisplayAdapterLocked(new HeadlessDisplayAdapter(
                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
            } else {
                //走这个分支
                registerDisplayAdapterLocked(new LocalDisplayAdapter(
                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
            }
        }
    }

LocalDisplayAdapter 构造函数的 mHandler 和 mDisplayAdapterListener 分别为 DisplayManagerHandler 和 DisplayAdapterListener。

/*--------------LocalDisplayAdapter.java---------------------------*/
    /* class LocalDisplayAdapter extends DisplayAdapter */
    // Called with SyncRoot lock held.
    public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
            Context context, Handler handler, Listener listener) {
        super(syncRoot, context, handler, listener, TAG);
    }
    /*--------------DisplayAdapter.java---------------------------*/
   // LocalDisplayAdapter是 DisplayAdapter的子类
   public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
            Context context, Handler handler, Listener listener, String name) {
        mSyncRoot = syncRoot;
        mContext = context;
        mHandler = handler;
        mListener = listener;
        mName = name;
    }
/*--------------DisplayManagerService.java---------------------------*/
//    private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
        private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
        mDisplayAdapters.add(adapter);
        adapter.registerLocked();
    }

LocalDisplayAdapter.registerLocked(),

/*--------------LocalDisplayAdapter.java---------------------------*/       
        private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
            SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
            SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
    };

    // LocalDisplayAdapter.registerLocked
        public void registerLocked() {
        super.registerLocked();

        mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
    //对默认屏幕和HDMI调用tryConnectDisplayLocked
        for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
            tryConnectDisplayLocked(builtInDisplayId);
        }
    }

调用 tryConnectDisplayLocked (),这里主要是和底层 framework 去交互,获取底层注册的 displays 的相关信息。

/*--------------LocalDisplayAdapter.java---------------------------*/ 
      // LocalDisplayAdapter.mDevices 
      // private final SparseArray<LocalDisplayDevice> mDevices =new SparseArray<LocalDisplayDevice>();
      private void tryConnectDisplayLocked(int builtInDisplayId) {
      //获取surface flinger中的new BBinder对应的client IBinder
        IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
        //获取display的硬件属性,新建LocalDisplayDevice
        if (displayToken != null && SurfaceControl.getDisplayInfo(displayToken, mTempPhys)) {
            LocalDisplayDevice device = mDevices.get(builtInDisplayId);
            if (device == null) {
                // Display was added.
                device = new LocalDisplayDevice(displayToken, builtInDisplayId, mTempPhys);
                mDevices.put(builtInDisplayId, device);
                //给DisplayManagerService的DisplayManagerHandler发消息
                sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
            } else if (device.updatePhysicalDisplayInfoLocked(mTempPhys)) {
                // Display properties changed.
                sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
            }
        } else {
            // The display is no longer available. Ignore the attempt to add it.
            // If it was connected but has already been disconnected, we''ll get a
            // disconnect event that will remove it from mDevices.
        }
    }
/*--------------SurfaceControl.java---------------------------*/
    //SurfaceControl.java,都是static,类函数
    //通过id获取display token
    public static IBinder getBuiltInDisplay(int builtInDisplayId) {
        return nativeGetBuiltInDisplay(builtInDisplayId);
    }
        //通过display token,获取display硬件属性
        public static boolean getDisplayInfo(IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo) {
        if (displayToken == null) {
            throw new IllegalArgumentException("displayToken must not be null");
        }
        if (outInfo == null) {
            throw new IllegalArgumentException("outInfo must not be null");
        }
        return nativeGetDisplayInfo(displayToken, outInfo);
    }

其中,nativeGetBuiltInDisplay 最终会调用 surfaceflinger 中的 getBuiltInDisplay,通过 Binder 传回代理对象。

/*--------------SurfaceFlinger.cpp---------------------------*/
sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
    if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
        ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
        return NULL;
    }
    return mBuiltinDisplays[id];
}

nativeGetDisplayInfo—>SurfaceFlinger::getDisplayInfo,

/*--------------SurfaceFlinger.cpp---------------------------*/
status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
    int32_t type = NAME_NOT_FOUND;
    for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
        if (display == mBuiltinDisplays[i]) {
            type = i;
            break;
        }
    }

    if (type < 0) {
        return type;
    }

    const HWComposer& hwc(getHwComposer());
    float xdpi = hwc.getDpiX(type);
    float ydpi = hwc.getDpiY(type);

    // TODO: Not sure if display density should handled by SF any longer
    class Density {
        static int getDensityFromProperty(char const* propName) {
            char property[PROPERTY_VALUE_MAX];
            int density = 0;
            if (property_get(propName, property, NULL) > 0) {
                density = atoi(property);
            }
            return density;
        }
    public:
        static int getEmuDensity() {
            return getDensityFromProperty("qemu.sf.lcd_density"); }
        static int getBuildDensity()  {
            return getDensityFromProperty("ro.sf.lcd_density"); }
    };

    if (type == DisplayDevice::DISPLAY_PRIMARY) {
        // The density of the device is provided by a build property
        float density = Density::getBuildDensity() / 160.0f;
        if (density == 0) {
            // the build doesn''t provide a density -- this is wrong!
            // use xdpi instead
            ALOGE("ro.sf.lcd_density must be defined as a build property");
            density = xdpi / 160.0f;
        }
        if (Density::getEmuDensity()) {
            // if "qemu.sf.lcd_density" is specified, it overrides everything
            xdpi = ydpi = density = Density::getEmuDensity();
            density /= 160.0f;
        }
        info->density = density;

        // TODO: this needs to go away (currently needed only by webkit)
        sp<const DisplayDevice> hw(getDefaultDisplayDevice());
        info->orientation = hw->getOrientation();
    } else {
        // TODO: where should this value come from?
        static const int TV_DENSITY = 213;
        info->density = TV_DENSITY / 160.0f;
        info->orientation = 0;
    }

    info->w = hwc.getWidth(type);
    info->h = hwc.getHeight(type);
    info->xdpi = xdpi;
    info->ydpi = ydpi;
    info->fps = float(1e9 / hwc.getRefreshPeriod(type));

    // All non-virtual displays are currently considered secure.
    info->secure = true;

    return NO_ERROR;
}

创建完 LocalDisplayDevice,给 DisplayManagerService 的 DisplayManagerHandler 发消息,

/*--------------DisplayAdapter.java---------------------------*/
    /**
     * Sends a display device event to the display adapter listener asynchronously.
     */
    protected final void sendDisplayDeviceEventLocked(
            final DisplayDevice device, final int event) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mListener.onDisplayDeviceEvent(device, event);
            }
        });
    }

LocalDisplayAdapter 构造函数的 mHandler 和 mDisplayAdapterListener 分别为 DisplayManagerHandler 和 DisplayAdapterListener,进而会去调用,

/*--------------DisplayManagerService.java---------------------------*/
        private void handleDisplayDeviceAdded(DisplayDevice device) {
        synchronized (mSyncRoot) {
            handleDisplayDeviceAddedLocked(device);
        }
    }
/*--------------DisplayManagerService.java---------------------------*/
    //输入为LocalDisplayDevice
    //    private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>();
    private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
        if (mDisplayDevices.contains(device)) {
            Slog.w(TAG, "Attempted to add already added display device: "
                    + device.getDisplayDeviceInfoLocked());
            return;
        }

        Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
    // List of all currently connected display devices.
    //将LocalDisplayDevice添加到mDisplayDevices
        mDisplayDevices.add(device);
        //为一个物理display添加一个logical display
        addLogicalDisplayLocked(device);
        updateDisplayBlankingLocked(device);
        scheduleTraversalLocked(false);
    }

为物理屏幕创建一个 logical display,

/*--------------DisplayManagerService.java---------------------------*/
// Adds a new logical display based on the given display device.
    // Sends notifications if needed.
    private void addLogicalDisplayLocked(DisplayDevice device) {
        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
        boolean isDefault = (deviceInfo.flags
                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
        //主屏,同时mLogicalDisplays包含了这个device
        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
            Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
            isDefault = false;
        }
        //不是主屏,但是mSingleDisplayDemoMode为真,即设置了单屏模式
        //这时候不会去为这个物理display创建新的logical display,如果
        //有hdmi,这时候会mirror主屏的内容
        //看来逻辑display就是和显示的内容有很大的关系
        if (!isDefault && mSingleDisplayDemoMode) {
            Slog.i(TAG, "Not creating a logical display for a secondary display "
                    + " because single display demo mode is enabled: " + deviceInfo);
            return;
        }

        final int displayId = assignDisplayIdLocked(isDefault);
        // layerStack 就是displayId id,主屏0,hdmi 1
        final int layerStack = assignLayerStackLocked(displayId);

        //新建LogicalDisplay
        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
        display.updateLocked(mDisplayDevices);
        if (!display.isValidLocked()) {
            // This should never happen currently.
            Slog.w(TAG, "Ignoring display device because the logical display "
                    + "created from it was not considered valid: " + deviceInfo);
            return;
        }

        mLogicalDisplays.put(displayId, display);

        //如果添加的是built-in display,需要mSyncRoot.notifyAll()
        //因为systemserver.java中调用了waitForDefaultDisplay,这时候systemserver可以继续运行了
        // Wake up waitForDefaultDisplay.
        if (isDefault) {
            mSyncRoot.notifyAll();
        }
    //给mHandler发消息去处理
        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
    }
/*--------------LogicalDisplay.java---------------------------*/
    public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
        mDisplayId = displayId;
        mLayerStack = layerStack;
        mPrimaryDisplayDevice = primaryDisplayDevice;
    }

进而去调用 mHandler 的 deliverDisplayEvent,先不去管 mCallbacks 是在哪里注册的,进而会去调用 mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);

/*--------------DisplayManagerService.java---------------------------*/
   private void deliverDisplayEvent(int displayId, int event) {
        if (DEBUG) {
            Slog.d(TAG, "Delivering display event: displayId="
                    + displayId + ", event=" + event);
        }

        // Grab the lock and copy the callbacks.
        final int count;
        synchronized (mSyncRoot) {
        //这里的mCallbacks是哪里注册的??
            count = mCallbacks.size();
            mTempCallbacks.clear();
            for (int i = 0; i < count; i++) {
                mTempCallbacks.add(mCallbacks.valueAt(i));
            }
        }

        // After releasing the lock, send the notifications out.
        for (int i = 0; i < count; i++) {
            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
        }
        mTempCallbacks.clear();
    }

2. mCallbacks 的由来, 上面在添加了默认 display 的 LogicalDisplay 后,会去调用下面代码,使得 systemserver.java 从 waitForDefaultDisplay () 中返回。

/*--------------systemserver.java---------------------------*/
        if (isDefault) {
            mSyncRoot.notifyAll();
        }

进而,systemserver.java 的 initAndLoop () 会去注册 WindowManagerService,

/*--------------systemserver.java---------------------------*/
            wm = WindowManagerService.main(context, power, display, inputManager,
                    wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
                    !firstBoot, onlyCore);

下面分析下,WindowManagerService 的构造函数中做了什么和 display 相关的,

/*--------------WindowManagerService.java---------------------------*/
/*
class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
                DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener
*/
    //WindowManagerService实现了DisplayManager.DisplayListener接口

    private WindowManagerService(Context context, PowerManagerService pm,
            DisplayManagerService displayManager, InputManagerService inputManager,
            boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {

    mDisplayManagerService = displayManager;
    //新建个DisplayManager
    mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
    //由于WindowManagerService实现了DisplayManager.DisplayListener接口,
    //将WindowManagerService注册到DisplayManager中
    mDisplayManager.registerDisplayListener(this, null);    

    }
/*--------------DisplayManager.java---------------------------*/
        public DisplayManager(Context context) {
        mContext = context;
        mGlobal = DisplayManagerGlobal.getInstance();
    }
/*--------------DisplayManagerGlobal.java---------------------------*/

// class DisplayManagerService extends IDisplayManager.Stub 
   public static DisplayManagerGlobal getInstance() {
        synchronized (DisplayManagerGlobal.class) {
            if (sInstance == null) {
                IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
                if (b != null) {
                //输入参数是DisplayManagerService 的代理
                    sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
                }
            }
            return sInstance;
        }
    }

public final class DisplayManagerGlobal {

    //mDm是DisplayManagerService 的代理,用来和DisplayManagerService打交道
    private final IDisplayManager mDm;

        private DisplayManagerGlobal(IDisplayManager dm) {
        mDm = dm;
    }

}

接着将 WindowManagerService 注册到 DisplayManager 中,

/*--------------DisplayManager.java---------------------------*/
        //输入参数为WindowManagerService,null    
        public void registerDisplayListener(DisplayListener listener, Handler handler) {
        mGlobal.registerDisplayListener(listener, handler);
    }
/*--------------DisplayManagerGlobal.java---------------------------*/
        // DisplayManagerGlobal 
        public void registerDisplayListener(DisplayListener listener, Handler handler) {
        if (listener == null) {
            throw new IllegalArgumentException("listener must not be null");
        }
   // private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
    //        new ArrayList<DisplayListenerDelegate>();
        synchronized (mLock) {
            int index = findDisplayListenerLocked(listener);
            if (index < 0) {
             //新建一个display listener的代理者
                mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
             //将DisplayManagerGlobal 和DisplayManagerService 联系起来
            registerCallbackIfNeededLocked();
            }
        }
    }

 public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
            super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
            mListener = listener;
        }
/*--------------DisplayManagerGlobal.java---------------------------*/
// 将    DisplayManagerGlobal 和DisplayManagerService 联系起来
        private void registerCallbackIfNeededLocked() {
        if (mCallback == null) {
            mCallback = new DisplayManagerCallback();
            try {
                //调用DisplayManagerService 的registerCallback将
                //DisplayManagerGlobal 中的DisplayManagerCallback注册到DisplayManagerService中
                mDm.registerCallback(mCallback);
            } catch (RemoteException ex) {
                Log.e(TAG, "Failed to register callback with display manager service.", ex);
                mCallback = null;
            }
        }
    }   
private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
        @Override
        public void onDisplayEvent(int displayId, int event) {
            if (DEBUG) {
                Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
            }
            handleDisplayEvent(displayId, event);
        }
    }

DisplayManagerService 中调用 registerCallback,将 DisplayManagerCallback 保存到 mCallbacks 中,

/*--------------DisplayManagerService.java---------------------------*/
  @Override // Binder call
    public void registerCallback(IDisplayManagerCallback callback) {
        if (callback == null) {
            throw new IllegalArgumentException("listener must not be null");
        }

        synchronized (mSyncRoot) {
            int callingPid = Binder.getCallingPid();
            if (mCallbacks.get(callingPid) != null) {
                throw new SecurityException("The calling process has already "
                        + "registered an IDisplayManagerCallback.");
            }

            CallbackRecord record = new CallbackRecord(callingPid, callback);
            try {
                IBinder binder = callback.asBinder();
                binder.linkToDeath(record, 0);
            } catch (RemoteException ex) {
                // give up
                throw new RuntimeException(ex);
            }
        //保存的是CallbackRecord 
            mCallbacks.put(callingPid, record);
        }
    }
/*--------------DisplayManagerService.java---------------------------*/
    private final class CallbackRecord implements DeathRecipient {
        public final int mPid;
        private final IDisplayManagerCallback mCallback;

        public boolean mWifiDisplayScanRequested;

        public CallbackRecord(int pid, IDisplayManagerCallback callback) {
            mPid = pid;
            mCallback = callback;
        }

        @Override
        public void binderDied() {
            if (DEBUG) {
                Slog.d(TAG, "Display listener for pid " + mPid + " died.");
            }
            onCallbackDied(this);
        }

        public void notifyDisplayEventAsync(int displayId, int event) {
            try {
                mCallback.onDisplayEvent(displayId, event);
            } catch (RemoteException ex) {
                Slog.w(TAG, "Failed to notify process "
                        + mPid + " that displays changed, assuming it died.", ex);
                binderDied();
            }
        }
    }

3. 回到最开始的 deliverDisplayEvent 函数,会调用 CallbackRecord 的 notifyDisplayEventAsync (displayId, event),进而 mCallback.onDisplayEvent(displayId, event),进而调用 DisplayManagerGlobal 的 handleDisplayEvent(displayId, event)

/*--------------DisplayManagerService.java---------------------------*/
 private void deliverDisplayEvent(int displayId, int event) {
        if (DEBUG) {
            Slog.d(TAG, "Delivering display event: displayId="
                    + displayId + ", event=" + event);
        }

        // Grab the lock and copy the callbacks.
        final int count;
        synchronized (mSyncRoot) {
        //这里的mCallbacks是哪里注册的??
            count = mCallbacks.size();
            mTempCallbacks.clear();
            for (int i = 0; i < count; i++) {
                mTempCallbacks.add(mCallbacks.valueAt(i));
            }
        }

        // After releasing the lock, send the notifications out.
        for (int i = 0; i < count; i++) {
            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
        }
        mTempCallbacks.clear();
    }

handleDisplayEvent 中的 mDisplayListeners 就是前面注册的 DisplayListenerDelegate,其中的 listener 和 handler 分别为 WindowManagerService 和 null,


/*--------------DisplayManagerGlobal.java---------------------------*/
    private void handleDisplayEvent(int displayId, int event) {
        synchronized (mLock) {
            if (USE_CACHE) {
                mDisplayInfoCache.remove(displayId);

                if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) {
                    mDisplayIdCache = null;
                }
            }

            final int numListeners = mDisplayListeners.size();
            for (int i = 0; i < numListeners; i++) {
                mDisplayListeners.get(i).sendDisplayEvent(displayId, event);
            }
        }
    }

调用 DisplayListenerDelegate 的 sendDisplayEvent,进而调用 mListener.onDisplayAdded(msg.arg1);,即 WindowManagerService 的 onDisplayAdded,


/*--------------DisplayManagerGlobal.java---------------------------*/
 private static final class DisplayListenerDelegate extends Handler {
        public final DisplayListener mListener;

        public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
            super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
            mListener = listener;
        }

        public void sendDisplayEvent(int displayId, int event) {
            Message msg = obtainMessage(event, displayId, 0);
            sendMessage(msg);
        }

        public void clearEvents() {
            removeCallbacksAndMessages(null);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case EVENT_DISPLAY_ADDED:
                    mListener.onDisplayAdded(msg.arg1);
                    break;
                case EVENT_DISPLAY_CHANGED:
                    mListener.onDisplayChanged(msg.arg1);
                    break;
                case EVENT_DISPLAY_REMOVED:
                    mListener.onDisplayRemoved(msg.arg1);
                    break;
            }
        }
    }
}

转到 WindowManagerService 中,

/*--------------WindowManagerService.java---------------------------*/
    @Override
    public void onDisplayAdded(int displayId) {
        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
    }
/*--------------WindowManagerService.java---------------------------*/
                    case DO_DISPLAY_ADDED:
                    synchronized (mWindowMap) {
                        handleDisplayAddedLocked(msg.arg1);
                    }
                    break;

        private void handleDisplayAddedLocked(int displayId) {
        final Display display = mDisplayManager.getDisplay(displayId);
        if (display != null) {
            createDisplayContentLocked(display);
            displayReady(displayId);
        }
    }

调用 DisplayManager 的 getDisplay,

/*--------------DisplayManager.java---------------------------*/
        public Display getDisplay(int displayId) {
        synchronized (mLock) {
            return getOrCreateDisplayLocked(displayId, false /*assumeValid*/);
        }
    }
/*--------------DisplayManager.java---------------------------*/
    //  private final SparseArray<Display> mDisplays = new SparseArray<Display>();
        private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
        Display display = mDisplays.get(displayId);
        if (display == null) {
            display = mGlobal.getCompatibleDisplay(displayId,
                    mContext.getDisplayAdjustments(displayId));
            if (display != null) {
                mDisplays.put(displayId, display);
            }
        } else if (!assumeValid && !display.isValid()) {
            display = null;
        }
        return display;
    }
/*--------------DisplayManagerGlobal.java---------------------------*/

    public Display getCompatibleDisplay(int displayId, DisplayAdjustments daj) {
        DisplayInfo displayInfo = getDisplayInfo(displayId);
        if (displayInfo == null) {
            return null;
        }
        return new Display(this, displayId, displayInfo, daj);
    }
/*--------------DisplayManagerGlobal.java---------------------------*/
//mDm DisplayManagerService
     public DisplayInfo getDisplayInfo(int displayId) {
        try {
            synchronized (mLock) {
                DisplayInfo info;
                if (USE_CACHE) {
                    info = mDisplayInfoCache.get(displayId);
                    if (info != null) {
                        return info;
                    }
                }
        //调用DisplayManagerService的getDisplayInfo,获取显示器信息
                info = mDm.getDisplayInfo(displayId);
                if (info == null) {
                    return null;
                }

                if (USE_CACHE) {
                    mDisplayInfoCache.put(displayId, info);
                }
                //前面已经注册过了,mCallback不为Null
                registerCallbackIfNeededLocked();

                if (DEBUG) {
                    Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
                }
                return info;
            }
        } catch (RemoteException ex) {
            Log.e(TAG, "Could not get display information from display manager.", ex);
            return null;
        }
    }
/*--------------DisplayManagerGlobal.java---------------------------*/
    //已经注册过了,mCallback不为Null
        private void registerCallbackIfNeededLocked() {
        if (mCallback == null) {
            mCallback = new DisplayManagerCallback();
            try {
                mDm.registerCallback(mCallback);
            } catch (RemoteException ex) {
                Log.e(TAG, "Failed to register callback with display manager service.", ex);
                mCallback = null;
            }
        }
    }
/*--------------WindowManagerService.java---------------------------*/
    //Display已经创建,创建display content
    public void createDisplayContentLocked(final Display display) {
        if (display == null) {
            throw new IllegalArgumentException("getDisplayContent: display must not be null");
        }
        getDisplayContentLocked(display.getDisplayId());
    }
/** All DisplayContents in the world, kept here */
    // SparseArray<DisplayContent> mDisplayContents = new SparseArray<DisplayContent>(2);

        public DisplayContent getDisplayContentLocked(final int displayId) {
        DisplayContent displayContent = mDisplayContents.get(displayId);
        if (displayContent == null) {
            final Display display = mDisplayManager.getDisplay(displayId);
            // 走到这个分支,创建displayContent 
            if (display != null) {
                displayContent = newDisplayContentLocked(display);
            }
        }
        return displayContent;
    }

新建一个 DisplayContent,保存到 WindowManagerService 的 mDisplayContents (displayId, displayContent)。

private DisplayContent newDisplayContentLocked(final Display display) {
        DisplayContent displayContent = new DisplayContent(display, this);
        final int displayId = display.getDisplayId();
        mDisplayContents.put(displayId, displayContent);

        DisplayInfo displayInfo = displayContent.getDisplayInfo();
        final Rect rect = new Rect();
        mDisplaySettings.getOverscanLocked(displayInfo.name, rect);
        synchronized (displayContent.mDisplaySizeLock) {
            displayInfo.overscanLeft = rect.left;
            displayInfo.overscanTop = rect.top;
            displayInfo.overscanRight = rect.right;
            displayInfo.overscanBottom = rect.bottom;
            mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
                    displayId, displayInfo);
        }
        configureDisplayPolicyLocked(displayContent);

        // TODO: Create an input channel for each display with touch capability.
        if (displayId == Display.DEFAULT_DISPLAY) {
            displayContent.mTapDetector = new StackTapPointerEventListener(this, displayContent);
            registerPointerEventListener(displayContent.mTapDetector);
        }

        return displayContent;
    }

Android apk 在 Android Studio 测试中非常完美,但在 Google Play 封闭测试中失败

Android apk 在 Android Studio 测试中非常完美,但在 Google Play 封闭测试中失败

如何解决Android apk 在 Android Studio 测试中非常完美,但在 Google Play 封闭测试中失败?

我正在制作一个 VPN 应用程序,它在 Android Studio 中完美编译,没有错误。此外,一旦它被发送到我的手机,它就会完美运行:它连接到 VPN 等。

将已签名的捆绑包上传到 Google Play 封闭式或内部测试后,我下载应用程序并进行安装,并观察到以下情况:

  1. 它请求创建 vpn 隧道
  2. 根本无法连接到 vpn 服务器

它正在使用 openvpn 库。

到目前为止,我已经通过各种方式尝试了 56 次构建。

我不知道,因为 Google 也没有检测到任何重要的应用问题

如果您有任何线索,请提前感谢

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

Android Audio:AudioTrack构造函数分析

Android Audio:AudioTrack构造函数分析

分析AudioTrack之前先分析一下AudioTrack和MediaPlayer的区别:

  • AudioTrack 只能播放 pcm 原始数据,不能播放视频。

  • MediaPlayer 可以播放视频和音频。

  • AudioTrack 只支持 pcm 原始音频数据。

  • MediaPlayer 支持 mp3,wav,aac…

  • MediaPlayer 在底层会创建指定的格式的解码器,将音频数据转化为 pcm 然后再交给 pcm
    去播放。MediaPlayer底层会创建 AudioTrack,将解码后的数据交给 AudioTrack 播放。

  • 每一个音频流对应着一个AudioTrack类的一个实例,每个AudioTrack会在创建时注册到
    audioflinger中,由audioflinger把所有的AudioTrack进行混合(mixer),然后输送到AudioHardware中进行播放,目前Android同时最多可以创建32个音频流,也就是说,mixer最多会同时处理32个AudioTrack的数据流。

个人感觉AudioTrack梳理起来的过程是非常痛苦的,中间可能也有很多问题,参考了很多博客,还有实习师傅的指导,整理一篇Android P的AudioTrack流程初文出来,以后工作用的多了熟悉了,再修改。

AudioTrack的构造函数分析:

android\frameworks\base\media\java\android\media\AudioTrack.java

走private的构造函数。

在这里插入图片描述


获取主线程的Looper,异步消息通信的机制。

在这里插入图片描述


获取采样率,声道掩码,编码类型,然后验证参数是否合法

在这里插入图片描述


调用native层的native_setup

在这里插入图片描述


native_setup()

在这里插入图片描述


android\frameworks\base\core\jni\android_media_AudioTrack.cpp

在这里插入图片描述


进入JNI层

在这里插入图片描述


创建native层的AudioTrack。

在这里插入图片描述


android\frameworks\av\media\libaudioclient\AudioTrack.cpp

进到lib层,通过set()方法将参数设置进去

在这里插入图片描述


status_t AudioTrack::set()

在这里插入图片描述


创建IAudioTrack.

在这里插入图片描述


获取音频策略服务。

在这里插入图片描述


frameworks\av\media\libaudioclient\AudioSystem.cpp
通过binder机制绑定服务。

在这里插入图片描述


android\frameworks\av\media\libaudioclient\AudioTrack.cpp
进入audioflinger

在这里插入图片描述


android\frameworks\av\services\audioflinger\audioflinger.cpp

在这里插入图片描述


依据播放线程ID号查找出相应的PlaybackThread,依据客户端进程pid查找是否已经为该客户进程创建了Client对象。假设没有,则创建一个Client对象。

在这里插入图片描述


依据进程pid。为请求播放音频的client创建一个Client对象。

在这里插入图片描述


audioflinger的成员变量mClients以键值对的形式保存pid和Client对象。这里首先取出pid相应的Client对象,假设该对象为空。则为client进程创建一个新的Client对象。MemoryDealer是个工具类。用于分配共享内存。每个Client都拥有一个MemoryDealer对象,这就意味着每个client进程都是在自己独有的内存空间中分配共享内存。

在这里插入图片描述


创建了如同所示的内存大小。

在这里插入图片描述


返回继续看audioflinger::createTrack()

在这里插入图片描述


frameworks\av\services\audioflinger\Threads.cpp
创建Track对象

在这里插入图片描述


前面进行一系列的参数赋值,最后返回一个track对象。

在这里插入图片描述


进入Track的构造函数,由图可见,继承于TrackBase,因此先进入TrackBase的构造函数进行分析。

在这里插入图片描述


TrackBase()
thread,所属播放线程,client所属的客户端,sampleRate,采样率,format音频格式,channelMask,声道,frameCount,音频帧个数。sharedBuffer,共享内存。

在这里插入图片描述


得到应用进程id

在这里插入图片描述


计算存放音频的buffer大小。

在这里插入图片描述


Client不为空。就通过Client来分配buffer,为空,则通过mallc动态分配。

在这里插入图片描述


由此可见,TrackBase构造过程主要是为音频播放分配共享内存。
接着进入Track的构造函数进行分析。

在这里插入图片描述

为0创建AudioTrackServerProxy代理对象,不为0,创建StaticAudioTrackServerProxy代理对象;

在这里插入图片描述


接下来我们返回audioflinger的createTrack函数中,来看这个track对象到底做了什么事情。

android\frameworks\av\services\audioflinger\audioflinger.cpp

创建Track的binder对象TrackHandle,Track由于需要通过binder返回给AudioTrack,因此是个binder对象,该对象会包含share buffer的信息。由于share buffer不止会在audioflinger这端被读取,还会在AudioTrack这端被写入,因此创建出来的Track需要被传送回AudioTrack。而在binder间传送对象只有binder对象,因此需要构建binder对象TrackHandle,返回给AudioTrack。

在这里插入图片描述


frameworks\av\services\audioflinger\Tracks.cpp
至此,createTrack_l在audioflinger这端的工作基本完成了。

在这里插入图片描述

ps:这里我绕的不太清楚:可参考其他博客:[Android] createTrack_l

frameworks\av\media\libaudioclient\AudioTrack.cpp

返回AudioTrack.cpp中的creatTrack中。

在这里插入图片描述


构造函数暂时分析至此。

在这里插入图片描述

猫鸷 发布了38 篇原创文章 · 获赞 12 · 访问量 1万+ 私信 关注

Android audioManager解决MediaPlayer AudioTrack 调节音量问

Android audioManager解决MediaPlayer AudioTrack 调节音量问

在听筒模式下


am.setSpeakerphoneOn(false);    
setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);    
am.setMode(AudioManager.MODE_IN_CALL);  
我用Mediaplayer AudioTrack调节音量总是失败 


at.setStereoVolume(vol, vol);    
player.setVolume(vol,vol);  
后来 决定用AudioManager来调节音量


AudioManager可以修改系统Android系统的音量 


下面介绍几个AudioManager的几个音量调整方面的方法. 


首先是得到AudioManager实例: 


AudioManager am=(AudioManager)getSystemService(Context.AUDIO_SERVICE);  


调整音量方法有两种,一种是渐进式,即像手动按音量键一样,一步一步增加或减少,另一种是直接设置音量值. 


1、渐进式 


public void adjustStreamVolume (int streamType, int direction, int flags)    
   
am.adjustStreamVolume (AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);  
解释一下三个参数 


第一个streamType是需要调整音量的类型,这里设的是媒体音量,可以是:    
STREAM_ALARM 警报    
STREAM_MUSIC 音乐回放即媒体音量    
STREAM_NOTIFICATION 窗口顶部状态栏Notification,    
STREAM_RING 铃声    
STREAM_SYSTEM 系统    
STREAM_VOICE_CALL 通话    
STREAM_DTMF 双音多频,不是很明白什么东西    
   
第二个direction,是调整的方向,增加或减少,可以是:    
ADJUST_LOWER 降低音量    
ADJUST_RAISE 升高音量    
ADJUST_SAME 保持不变,这个主要用于向用户展示当前的音量    
   
第三个flags是一些附加参数,只介绍两个常用的    
FLAG_PLAY_SOUND 调整音量时播放声音    
FLAG_SHOW_UI 调整时显示音量条,就是按音量键出现的那个  
2、直接设置音量值的方法: 


public void setStreamVolume (int streamType, int index, int flags)    
   
am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), AudioManager.FLAG_PLAY_SOUND);    
am.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);//得到听筒模式的最大值    
am.getStreamVolume(AudioManager.STREAM_VOICE_CALL);//得到听筒模式的当前值  
第一个和第三个参数与上面的相同 


第二个参数是一个音量的int值,getStreamMaxVolume(int streamType)得到的是该类型音量的最大值,可以根据这个值计算你需要的音量,我这里直接调到最大.


最后我的代码: 


package com.lp;    
   
   
import java.io.File;    
import java.io.FileInputStream;    
import java.io.FileNotFoundException;    
import java.io.IOException;    
import java.io.InputStream;    
   
import android.app.Activity;    
import android.content.Context;    
import android.media.AudioFormat;    
import android.media.AudioManager;    
import android.media.AudioTrack;    
import android.os.Bundle;    
import android.view.View;    
import android.view.View.OnClickListener;    
import android.widget.Button;    
import android.widget.SeekBar;    
/**   
 * AudioTrack 播放音频 如wav格式   
 * 并允许调节音量   
 * @author Administrator   
 *   
 */   
public class MainActivity5 extends Activity {    
    private Button play;    
    private Button stop;    
    private SeekBar soundValue;    
        
    private AudioTrack at;    
    private AudioManager am;    
    @Override   
    public void onCreate(Bundle savedInstanceState) {    
        super.onCreate(savedInstanceState);    
        setContentView(R.layout.main_sk);    
        am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);    
        play = (Button)findViewById(R.id.main_sk_play);    
        stop = (Button)findViewById(R.id.main_sk_stop);    
        soundValue = (SeekBar)findViewById(R.id.skbVolume);    
        setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);    
        play.setOnClickListener(new OnClickListener() {    
            @Override   
            public void onClick(View v) {    
                    
                if(am.isSpeakerphoneOn()){    
                    am.setSpeakerphoneOn(false);    
                }    
                //setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);    
                am.setMode(AudioManager.MODE_IN_CALL);    
                System.out.println(am.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL));    
                System.out.println("&&&&&&&&&&&&&");    
                System.out.println(am.getStreamVolume(AudioManager.STREAM_VOICE_CALL));    
                //am.setStreamVolume(streamType, index, flags)    
                    
                int bufferSizeInBytes = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);    
                    
                if(at==null){    
                    at = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes, AudioTrack.MODE_STREAM);    
                    System.out.println("22222");    
                    //at.setStereoVolume(100f, 100f);    
                    at.setStereoVolume(0.7f, 0.7f);//设置当前音量大小    
                    new AudioTrackThread().start();    
                }else{    
                    if(at.getPlayState()==AudioTrack.PLAYSTATE_PLAYING){    
                        System.out.println("111111111");    
                    }else{    
                        System.out.println("33333");    
                        at = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes, AudioTrack.MODE_STREAM);    
                        new AudioTrackThread().start();    
                    }    
                }    
                    
            }    
        });    
            
        stop.setOnClickListener(new OnClickListener() {    
                
            @Override   
            public void onClick(View v) {    
                if(at.getPlayState()==AudioTrack.PLAYSTATE_PLAYING){    
                    try{    
                        at.stop();    
                    }catch (IllegalStateException e)    
                    {    
                        e.printStackTrace();    
                    }    
                    at.release();    
                    am.setMode(AudioManager.MODE_NORMAL);    
                }    
            }       
        });    
            
//        soundValue.setMax(100);//音量调节的极限    
//        soundValue.setProgress(70);//设置seekbar的位置值    
        soundValue.setMax(am.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL));    
        soundValue.setProgress(am.getStreamVolume(AudioManager.STREAM_VOICE_CALL));    
            
        soundValue.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {    
                
            @Override   
            public void onStopTrackingTouch(SeekBar seekBar) {    
//              float vol=(float)(seekBar.getProgress())/(float)(seekBar.getMax());    
//              System.out.println(vol);    
//              at.setStereoVolume(vol, vol);//设置音量    
                am.setStreamVolume(AudioManager.STREAM_VOICE_CALL, seekBar.getProgress(), AudioManager.FLAG_PLAY_SOUND);    
            }    
                
            @Override   
            public void onStartTrackingTouch(SeekBar seekBar) {    
                // TODO Auto-generated method stub    
            }    
                
            @Override   
            public void onProgressChanged(SeekBar seekBar, int progress,    
                    boolean fromUser) {    
                // TODO Auto-generated method stub    
            }    
        });    
    }    
        
    class AudioTrackThread extends Thread{      
   
        @Override   
        public void run() {    
            byte[] out_bytes = new byte[44100];    
                
            InputStream is = getResources().openRawResource(R.raw.start);        
            int length ;    
            try{    
                at.play();    
            }catch (IllegalStateException e)    
            {    
                e.printStackTrace();    
            }    
            try {    
                while((length = is.read(out_bytes))!=-1){    
                    //System.out.println(length);    
                    at.write(out_bytes, 0, length);    
                }    
            } catch (IOException e) {    
                e.printStackTrace();    
            }    
            if(at.getPlayState()==AudioTrack.PLAYSTATE_PLAYING){    
                try{    
                    at.stop();    
                }catch (IllegalStateException e)    
                {    
                    e.printStackTrace();    
                }    
                at.release();    
                am.setMode(AudioManager.MODE_NORMAL);    
            }    
        }    
            
    }    
                    
}  
当然 权限 


<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />    
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    
    <uses-permission android:name="android.permission.RECORD_AUDIO" />  


本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-10/44660.htm

我们今天的关于android – Kivy Play Audio不工作android audiomanager的分享就到这里,谢谢您的阅读,如果想了解更多关于(OK) Android graphic (12)—display 上层相关概念、关系 - mLogicalDisplays.get (Display.DEFAULT_DISPLAY)、Android apk 在 Android Studio 测试中非常完美,但在 Google Play 封闭测试中失败、Android Audio:AudioTrack构造函数分析、Android audioManager解决MediaPlayer AudioTrack 调节音量问的相关信息,可以在本站进行搜索。

本文标签: